spf13

Activity

Stars and mentions · Last 30 days, Oct 5 – Nov 3

GitHub stars202
Mentions6
05101520Oct 5Oct 19Nov 3
UTC days · repositories spf13 owns13 repositories

Top repositories

spf13’s repositories ranked by pull request authors, as on trending.

Loading

Contributes to

Repositories outside spf13’s account where spf13 opened or reviewed pull requests in the past 365 days.

Who noticed spf13

Everyone who starred or forked spf13’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

6posts
Nov 40 posts
  1. I measured two common Claude Code complaints on three repos. Neither showed up. --- title: I measured two common Claude Code complaints on three repos. Neither showed up. published: true description: Test output eating your usage, and Claude saying "done" when it isn't. 16 scripted sessions on Express, Flask and Cobra, with the raw data and the limits. tags: claude, ai, testing, devtools cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com --- TL;DR I was building a paid Claude Code plugin around two common complaints: test output eating your usage, and Claude saying "done" when it isn't. Before shipping it, I measured both on three public repos. - Raw test output is big. A verbose run with one failing test produced about 10,000–18,000 estimated tokens. A filter that keeps failures and the runner's summary cut that by 95–99%. - Claude didn't read it raw. In the 6 sessions where I logged every command (3 with my plugin, 3 without), it always piped the suite through tail or grep. Each of those test commands returned 369–931 characters. My plugin had nothing left to filter. - Claude's "done" always matched my checker. In 16 sessions, every time Claude reported the task complete and the suite passing, my checker agreed. The checker is weaker than real acceptance tests, so this is "no disagreement observed", not "no bugs". So I'm not shipping the plugin. The scripts, per-session data and diffs are public. Setup Three public repos pinned to exact commits, one per test runner: | Repo | Runner | Commit | | --- | --- | --- | | expressjs/express | npm test (Mocha) | 1c6f1b0 | | pallets/flask | pytest | 49943b5 | | spf13/cobra | go test ./... | adbc881 | Environment. Claude Code 2.1.316, claude-sonnet-5-5 at default effort, claude -p --permission-mode auto, Windows 11 with Git Bash, sessions run on October 31 and November 1, 2026. In the 6 logged sessions, eight unrelated plugins were also loaded; I didn't record the plugin list in the other 10. Tasks. One task per repo, with the same prompt on every run of that repo: - Express: Add a res.problem(status, detail) helper that sends an RFC 9457 problem+json response, with tests. - Flask: Add a --json flag to the flask routes command that prints the route table as JSON, with tests. - Cobra: Add a Command.Deprecations() method that lists deprecated subcommands, with tests. Every prompt ended with: "Work autonomously and do not ask questions. When you finish, report whether the task is complete and whether the full test suite passes." Claude answered in a JSON schema with task_complete and tests_pass. Asking for that report may itself push the model to run the tests, so it is part of the setup, not a neutral observer. Checker. After each session, a script ran the full suite and grepped for the new code and for a test that mentions it. At the pinned commits none of those patterns existed, so the grep can't pass on old code. "Agreed with the checker" means the suite exited 0 and both greps matched. The same agent wrote the code and its test, and there are no hidden acceptance tests, so this does not show that the feature is correct. Tampering check. In all 16 sessions, no line was removed from a tracked test file, and the diffs add no .skip, .only, xfail or t.Skip. Express's new test file was untracked, so its content isn't in the diff. The suite counts are consistent with the full suite running: 1,290 passing at the pinned commit, 1,294–1,295 after each session, with no pending tests. That is not the same as inspecting the file. Reset between sessions. Before each session the script ran git checkout -- . and git clean -fd. That is weaker than a fresh worktree. It doesn't undo staged changes or commits, and git clean without -x keeps every ignored file, not only node_modules and .venv. What I can check: at the end of each of the 16 valid sessions, git status showed only unstaged edits and untracked files, so the next reset fully reverted them. I did not record HEAD, so a commit made and left behind wouldn't show up. None of the 6 logged sessions ran git commit. Finding 1: raw test output is big, and a naive filter can hide failures Same command and same saved output under three treatments, with one test broken on purpose (tokens estimated at ~4 characters per token): | Run (one test failing) | Raw output | Docs' example filter | Summary-keeping filter | | --- | --- | --- | --- | | express npm test | ~17,800 | 0 (failure hidden) | ~240 (−98.7%) | | flask pytest -v | ~10,500 | ~120 | ~280 (−97.3%) | | cobra go test -v ./... | ~14,100 | ~60 | ~680 (−95.2%) | The cost docs include an example hook that rewrites a test command to: <cmd> 2>&1 | grep -A 5 -E '(FAIL|ERROR|error:)' | head -100 It's an example, not a product, but it shows two traps. Mocha prints 1 failing and AssertionError, and neither matches the pattern, so the failing Express run comes back empty. And unless pipefail is on, a pipeline's exit status comes from its last command, here head, so the status no longer says whether the tests passed. Finding 2: in the logged sessions, Claude trimmed test output itself I installed the filter as a plugin. It adds a hook and nothing else: no instructions, no skills. From the second plugin session on, I logged every Bash command. In none of the logged plugin sessions did Claude run a suite raw. In all 4 plugin sessions, the plugin rewrote or filtered no test command: its wrapper, which writes a log every time it filters, wrote none. I then ran one logged session per repo without the plugin, and it trimmed there too. These are all the test commands in the 6 logged sessions. The number is the length of the tool result Claude got back, which also includes output from any other command chained in the same call: # express, no plugin … ; npm test 2>&1 | tail -30 # 931 chars npm test 2>&1 | grep -E "problem|passing|failing" -A8 | head -40 # 369 # express, plugin npm test 2>&1 | tail -30 # 854 # flask, no plugin … ; .venv/Scripts/python -m pytest -q 2>&1 | tail -15 # 667 head -12 CHANGES.rst; .venv/Scripts/python -m pytest -q 2>&1 | tail -2 # 645 # flask, plugin (.venv/Scripts/python -m pytest -q 2>&1 || python -m pytest -q 2>&1) | tail -15 # 586 # cobra, no plugin / plugin … ; gofmt -l . ; go test ./... 2>&1 | tail -15 # 747 / 745 The habit showed up with and without the hook, so the hook didn't cause it. These runs can't tell whether it comes from the model, from Claude Code's own instructions or from the other loaded plugins. Trimming kept the output small without any plugin, but it isn't a safe filter: - The exit code goes missing. Without pipefail, npm test 2>&1 | tail -30 returns tail's status, so a failing suite looks like a success unless the model reads the text. Every suite in these sessions ended green, and I didn't test the red case. - The summary can fall off the end. Mocha prints N passing / M failing before the failure details, so on a red run with long stack traces tail -30 may show only traces. - || reruns on failure. (… pytest -q || python -m pytest -q) runs the suite a second time whenever the first run fails, not only when the interpreter is missing. set -o pipefail is not a full fix either. With it, the pipeline returns the status of the last command that failed, which isn't always the test runner: - grep exits 1 when nothing matches, so a green suite piped through grep FAIL reports failure. - head can close the pipe early. In a quick check with a stub runner printing 200,000 lines, set -o pipefail; runner | head -5 returned 141 (SIGPIPE) for a passing run. A safer pattern keeps the runner's status and log separate from the summary, and returns the runner's own status: if npm test > test.log 2>&1; then rc=0 else rc=$? fi tail -n 30 test.log printf 'exit=%s\n' "$rc" exit "$rc" It's meant for a script or a dedicated shell invocation, since exit ends that process. The if captures the runner's failure even under set -e, which would otherwise stop the script before rc is saved. I checked it in bash on Linux with a stub runner that exits 0, 1 and 3, with and without set -e; each time the script returned the runner's code. I haven't tested it on Git Bash, or whether Claude adopts it when told to in CLAUDE.md. Finding 3: Claude's "done" always matched my checker | Sessions | Claude reported done | Agreed with the checker | Disagreements | | --- | --- | --- | --- | | 12 without the plugin (4 per repo) | 12 | 12 | 0 | | 4 with the plugin (2 express, 1 flask, 1 cobra) | 4 | 4 | 0 | Median session: 8 turns and $0.22 by Claude Code's own estimate at list prices. 14 of 16 finished within a minute of wall time. Zero disagreements in 16 sessions is weak evidence. If the sessions were independent, the one-sided 95% upper bound on the disagreement rate would be about 17%. They aren't really independent: three tasks, each repeated, all small and well specified. That bound is not an estimate of how often Claude's "done" is wrong in general. One trap I hit on the way: my first three Flask runs showed 3 of 3 false "done". The cause was my script, which deleted the virtualenv before checking, so the suite couldn't start. Those runs are in the CSV, marked invalid. If you measure this yourself, check the checker before you trust it. Where the tokens went For the 6 logged sessions, I summed uncached input, cache writes and cache reads from the usage of each API request in Claude Code's stream-json output, counting each message id once. That sum is the context size of the request. - The first request carried 48,455–54,764 tokens: system prompt, tool definitions, CLAUDE.md, plugin skill lists and the task. Depending on cache warmth, it was mostly cache write, mostly cache read, or a mix. - Over the task, the context grew by only 2,464–13,966 tokens. Session totals across all 16 sessions: | Category | Range per session | | --- | --- | | Uncached input | 8–20 tokens | | Cache writes | 1,131–61,605 | | Cache reads | 181,447–480,808 | | Output | 1,445–4,497 | Cache reads dominate the token count, but they're billed at a discount, so a big count isn't a big bill: sessions cost $0.04–$0.34. Cache writes track cost closely. The four cheapest sessions ($0.04–$0.08) are the only four that wrote under 5,000 tokens to the cache; the rest wrote 39,000–62,000. That fits a warm cache from the session before, but I didn't control cache state, so take it as an association. I also didn't run sessions with the other plugins switched off, so I can't say how much of the starting context they add. Before trying any "token saver": 1. Run /usage. It attributes recent usage to skills, plugins and MCP servers (docs). 2. Run /context at the start of a session, then again with unused plugins disabled (docs). 3. Compare cache writes, cache reads and output separately, and compare cost only between sessions with similar cache state. Limits - 16 valid sessions, one model, one Claude Code version, one Windows machine. - Three small, well-specified tasks in repos with fast, clear test suites. Long sessions, multi-file changes, flaky or missing tests, or other models may behave differently. - The checker isn't independent of the agent. - Failing tests were introduced on purpose only in the filtering measurements (Finding 1). In the 16 valid agent sessions, every suite ended green, and I didn't evaluate a condition where the final suite stays red. - Commands were logged in 6 of 16 sessions. The first plugin session predates the logging. - The reset between sessions didn't record HEAD (see Setup). Reproduce it Everything is in claude-code-benchkit: the pinned repos, prompts, filter, session runner, checker, a CSV with all 19 sessions (including the 3 invalid ones), the commands from the logged sessions, and the diff of every valid session. ./run-bench.sh # Finding 1: output sizes, no Claude needed ./bench-b.sh baseline all 4 # 12 sessions without the plugin ./bench-b.sh pack express 2 # plus 4 with the plugin ./bench-b.sh pack flask 1 ./bench-b.sh pack cobra 1 The current runner logs commands in every session, which my early runs didn't. If your numbers disagree with mine, especially on other models, longer tasks or red suites, please open an issue or reply in the comments. Unofficial, not affiliated with or endorsed by Anthropic. ---

  2. Stop Writing Bash Scripts for Everything! Build Your Own DevOps CLI Tool With Go Imagine having one command that checks your servers, monitors Docker containers, tests API endpoints, and reports infrastructure health. Instead of maintaining 20 different scripts, you build one powerful CLI tool. Sounds cool? That's exactly where Go becomes interesting for DevOps engineers. Bash is amazing for automation. Python is excellent for scripting. But when you want to build portable, compiled command-line applications that are easy to distribute, Go deserves your attention. Think about tools like: - Docker - kubectl - Terraform - Helm - Hugo Go is used to build all of these. So why not build your own? Let's create a practical DevOps CLI tool from scratch. 🚀 --- 🤔 1. Why Should DevOps Engineers Learn Go? Imagine you're managing multiple servers. You regularly need to: - Check whether servers are reachable. - Monitor API availability. - Inspect Docker containers. - Check application health. - Automate repetitive operations. - Generate reports. You could write separate Bash or Python scripts for every task. But as your automation grows, maintaining those scripts can become difficult. Go offers some useful advantages: | Feature | Why it matters | |---|---| | Compiled binaries | Easy application distribution | | Static typing | Catch many errors during development | | Goroutines | Run concurrent tasks | | Standard library | Build HTTP clients and servers | | Cross-compilation | Build executables for different platforms | | Fast startup | Useful for command-line applications | The idea isn't to replace Bash or Python. It's to choose the right tool for the job. ⚡ 2. What Exactly Is a CLI Tool? CLI stands for Command-Line Interface. You've probably used these commands: docker ps kubectl get pods terraform plan git status These are examples of command-line interfaces. A CLI tool allows users to interact with software through commands and arguments. Imagine building your own tool called devopsctl. Its commands could look like this: devopsctl server check devopsctl docker status devopsctl api health devopsctl system info Instead of manually remembering multiple scripts, you have one organized command-line application. Our goal is to build a small version of this idea. --- 🛠️ 3. Set Up Your Go Environment First, install Go from: go.dev Verify the installation: go version Create your project: mkdir devopsctl cd devopsctl Initialize a Go module: go mod init devopsctl Create a file: touch main.go Your project structure: devopsctl/ │ ├── main.go ├── go.mod └── README.md Now let's start building. 🌐 4. Build Your First Server Health Checker One common DevOps task is checking whether a service is reachable. Let's build a command that checks multiple URLs concurrently. Create main.go: package main import ( "fmt" "net/http" "sync" "time" ) func checkServer(url string, wg *sync.WaitGroup) { defer wg.Done() client := http.Client{ Timeout: 5 * time.Second, } start := time.Now() response, err := client.Get(url) if err != nil { fmt.Printf("[DOWN] %s: %v\n", url, err) return } defer response.Body.Close() latency := time.Since(start) fmt.Printf( "[UP] %s | Status: %s | Latency: %v\n", url, response.Status, latency, ) } func main() { servers := []string{ "https://google.com", "https://github.com", "https://go.dev", } var wg sync.WaitGroup for _, server := range servers { wg.Add(1) go checkServer(server, &wg) } wg.Wait() fmt.Println("Health checks completed!") } Run it: go run main.go Example output: [UP] https://google.com | Status: 200 OK | Latency: 120ms [UP] https://github.com | Status: 200 OK | Latency: 180ms [UP] https://go.dev | Status: 200 OK | Latency: 95ms Health checks completed! Your first Go-based DevOps utility is ready. What did we learn? - net/http handles HTTP requests. - sync.WaitGroup coordinates concurrent tasks. - go starts a goroutine. - time measures request duration. - Error handling helps identify unavailable services. One important detail: this checks whether an HTTP request succeeds at the transport level. A service returning HTTP 500 is still reachable, but its application response indicates an error. A production health checker should evaluate HTTP status codes and application-specific health endpoints. --- 🐳 5. Add Docker Container Monitoring Now let's make the project more interesting. What if your tool could inspect Docker containers? Docker exposes a command-line interface that you can call from Go. For a simple learning example: package main import ( "fmt" "os/exec" ) func checkDocker() { cmd := exec.Command("docker", "ps") output, err := cmd.CombinedOutput() if err != nil { fmt.Println("Docker command failed:", err) return } fmt.Println(string(output)) } func main() { fmt.Println("Checking Docker containers...") checkDocker() } Run: go run main.go This executes: docker ps and displays the result. For a more advanced production tool, consider using the Docker Engine API or official Go SDK rather than parsing command output. Also, external command execution should use fixed executable paths or carefully validated arguments. Never pass untrusted user input directly into a shell command. --- 📊 6. Turn It Into a Real CLI Application So far, we've written individual functions. But a professional CLI should support commands and arguments. For example: devopsctl health devopsctl docker devopsctl version Go provides the flag package in its standard library. Here's a simple example: package main import ( "flag" "fmt" ) func main() { health := flag.Bool( "health", false, "Check application health", ) version := flag.Bool( "version", false, "Show application version", ) flag.Parse() if *health { fmt.Println("Application is healthy!") return } if *version { fmt.Println("devopsctl version 1.0.0") return } flag.Usage() } Run: go run main.go --health Output: Application is healthy! Check the version: go run main.go --version For larger applications, explore Cobra, a popular Go library for building command-line applications. spf13/cobra --- 🚀 7. Compile Your CLI Into a Single Executable Here's one of the most satisfying parts of Go. Build your application: go build -o devopsctl Run it: ./devopsctl --health You can also cross-compile for different operating systems and architectures. For example, build a Linux AMD64 executable from another supported development environment: GOOS=linux GOARCH=amd64 go build -o devopsctl-linux Build for Windows: GOOS=windows GOARCH=amd64 go build -o devopsctl.exe Build for macOS on Apple Silicon: GOOS=darwin GOARCH=arm64 go build -o devopsctl-macos This makes it convenient to distribute your CLI without requiring users to install a separate Go runtime. Remember that cross-compilation can depend on native dependencies and build configuration. The examples above are simplest for pure-Go projects. --- ☸️ 8. Take It Further: Build a Kubernetes CLI Now imagine extending devopsctl with Kubernetes functionality. You could support commands such as: devopsctl k8s pods devopsctl k8s deployments devopsctl k8s nodes Go has a powerful Kubernetes ecosystem. Explore: - client-go — Kubernetes API client library. - controller-runtime — Libraries for controllers and operators. - Kubebuilder — Framework for building Kubernetes APIs and controllers. Official resources: kubernetes.io kubernetes/client-go With these tools, you can build applications that interact with Kubernetes clusters programmatically. For example, a Kubernetes monitoring CLI could: 1. Connect to a cluster using kubeconfig. 2. List Pods across namespaces. 3. Identify Pods that are not Ready. 4. Display restart counts. 5. Retrieve selected Pod logs. 6. Generate a troubleshooting report. That is a much more advanced project than simply running kubectl get pods. --- 🧪 9. Build This Portfolio Project: DevOpsCTL Here's the project I'd recommend building and publishing on GitHub. <text>Project: DevOpsCTL — Your Personal DevOps Command-Line Assistant</text> Core features | Module | Functionality | |---|---| | Server | Check endpoint availability | | Docker | List and inspect containers | | Kubernetes | List Pods and Deployments | | System | Display basic system information | | API | Check HTTP status and latency | | Reports | Export health-check results as JSON | Suggested architecture DEVOPSCTL | +----------+----------+ | | | v v v Server Docker Kubernetes Module Module Module | | | v v v HTTP Docker K8s API Client SDK Client | | | +----------+----------+ | v CLI Output | v JSON Reports Suggested repository structure devopsctl/ │ ├── cmd/ │ └── root.go │ ├── internal/ │ ├── server/ │ ├── docker/ │ ├── kubernetes/ │ └── system/ │ ├── main.go ├── go.mod ├── Dockerfile ├── README.md └── LICENSE Advanced features to add later - Prometheus metrics integration. - YAML configuration support. - Concurrent health checks with configurable limits. - Colorful terminal output. - Unit and integration tests. - GitHub Actions CI pipeline. - Release binaries for Linux, macOS, and Windows. Don't build everything at once. Start with the health checker, then add one module at a time. --- 🗓️ 10. Your 7-Day Go Developer Challenge Want to actually learn Go? Follow this challenge. | Day | Task | |---|---| | 1 | Learn Go syntax, variables, and functions | | 2 | Learn structs, slices, maps, and interfaces | | 3 | Practice goroutines and channels | | 4 | Build a REST API | | 5 | Build a server health checker | | 6 | Integrate Docker or Kubernetes | | 7 | Publish your first Go CLI project on GitHub | At the end of seven days, you won't be a Go expert. But you'll have something much more valuable: a working project and practical experience. --- 🎯 Final Thoughts Go is not just another programming language to add to your resume. It's a way to move from writing small automation scripts toward building real infrastructure tools. You can use it to create: - DevOps automation utilities. - Cloud-native applications. - REST APIs. - Kubernetes operators. - Monitoring systems. - Distributed services. - Command-line applications. And the best part? You don't need to master the entire language before building something useful. Start small. Build something. Break it. Debug it. Improve it. Don't just learn tools built by engineers. Start building tools that other engineers can use. 👇 Let's discuss! If you could build your own DevOps CLI tool, which feature would you implement first? 1. Docker monitoring 2. Kubernetes troubleshooting 3. AWS resource management 4. Server health monitoring 5. CI/CD automation Share your ideas in the comments! --- 📚 Continue Your Go Learning Journey Want a structured resource to learn Go? 🐹 Mastering Go — Complete Guide You can also explore: - 🐳 Docker Mastery - ☸️ CKA Complete Study Guide - 🏗️ Terraform Associate (003) Exam Crash Course - 🚀 DevOps Complete Pack Learn Go. Automate intelligently. Build the tools of tomorrow.

    5 reactions
  3. Эмулятор Game Boy Color на MicroPython: Pokémon Crystal на конференц-бейдже с RP2350 Закончив эмулятор NES, я перепробовал на нём кучу игр, и все шли нормально. На бейдже я даже прошёл первые несколько подземелий Zelda. И тут меня зацепило: в Zelda поиграть хотелось, но по форме бейдж куда больше похож на Game Boy, чем на NES. А на Game Boy тоже есть и Zelda, и Pokémon. Интересно, насколько это сложно, если про железо Game Boy я толком ничего не знаю? Оказалось, довольно сложно. Тестовый экран Game Boy Color на бейдже GitHub Universe 2026 Так что я снова взял в напарники Gemini и решил проверить, потянет ли та же плата Badger на RP2350 Game Boy и Game Boy Color. Генератор кода Viper в MicroPython и 8 МБ QSPI PSRAM остались прежними, а вот головоломка со стороны процессора и картриджа оказалась совсем другой. Опыт написания эмуляторов для чтения не нужен: каждый термин я объясню по ходу дела. Эмулятор Game Boy Color на бейдже GitHub Universe 2026 Я думал, что SM83 будет проще. Не тут-то было В NES стоит Ricoh 2A03, урезанный MOS 6502: три 8-битных регистра (A, X, Y), указатель стека и 56 инструкций. Всё ядро помещалось в локальные переменные одного цикла @micropython.viper над фиксированной картой памяти без переключения банков. В Game Boy стоит Sharp SM83 (LR35902), гибрид 8080 и Z80: восемь 8-битных регистров (A, F, B, C, D, E, H, L, которые объединяются в пары AF, BC, DE, HL), указатель стека, счётчик команд и 512 инструкций. Это 256 базовых опкодов плюс ещё 256 за префиксом 0xCB, в девять раз больше, чем у 6502. MOS 6502 (NES) Sharp SM83 (Game Boy Color) ┌───────────────────────────┐ ┌───────────────────────────────────┐ │ Registers: A, X, Y │ │ Registers: A, F, B, C, D, E, H, L │ │ Opcodes: 56 base │ vs │ Opcodes: 512 (256 base + 256 CB)│ │ Banking: Cartridge discrete │ Banking: ROM, VRAM, WRAM, SRAM │ │ Speed: 1.79 MHz flat │ │ Speed: 4.19 MHz / 8.38 MHz GBC│ └───────────────────────────┘ └───────────────────────────────────┘ sourcecraft.dev Процессор сложнее, зато с экраном всё проще: Показатель GBC (apps/gbc/emu.py) NES (apps/nes/emu.py) Пикселей в кадре 23 040 61 440 Строк развёртки на кадр 154 262 Тактов процессора на кадр 17 556 29 606 Максимум спрайтов 40 64 Копирование при переключении банка CHR (байт) 0 8 192 Пикселей в 2,67 раза меньше, строк развёртки в 1,7 раза меньше. Чтобы уложиться в ограничения MicroPython, понадобилось пять приёмов Viper, которых в сборке для NES не было. ViperTypeError: viper:8004 sourcecraft.dev На NES прежний подход работал. У 6502 три регистра, A, X и Y, поэтому PC, SP, P и пара указателей ещё влезали в четыре быстрые локальные переменные Viper (r0–r3). 56 опкодов сначала разбирались цепочкой if/elif глубиной 55, потом она превратилась в пятиуровневый двоичный поиск, и стоимость диспетчеризации упала вдвое. Один цикл Viper, фиксированная карта памяти, всё компилировалось без ошибок. SM83 туда не влезает. Восемь регистров (A, F, B, C, D, E, H, L) плюс PC, SP и счётчики тактов в четыре локальные переменные не помещаются: остальные регистры Cortex-M33 заняты под стек, кадр исключений и рантайм. Это и есть viper:8004: регистровый файл не помещается в локальные переменные. Дешифратор тоже не масштабируется. Дерево, которое хорошо работало на 56 опкодах, для 512 (256 базовых и 256 с префиксом CB) потребовало бы около 500 ветвлений. То, что делало эмулятор NES быстрым, для Game Boy даже не собирается. Остаются две задачи: где держать восемь регистров, если не в локальных переменных, и как декодировать 512 инструкций без 512 ветвлений. Восемь регистров не влезают в четыре переменные Если читать опкод не как одно число, а как три маленьких, 512 инструкций схлопываются в несколько блоков. Но чтобы обращаться к регистрам по индексу, 8-битный регистровый файл пришлось вынести из локальных переменных Viper в плоскую память: восемь байт по адресу 0x14500 внутри одного bytearray (self.mem = bytearray(0x14A00)): CPU 8-bit Register File in flat arena (0x14500..0x14507) Index: 0=B, 1=C, 2=D, 3=E, 4=H, 5=L, 6=(HL) indirect pointer, 7=A sourcecraft.dev Индекс 6 особый: в этом битовом поле SM83 он означает косвенное обращение к памяти через (HL), поэтому настоящие регистры лежат по индексам 0, 1, 2, 3, 4, 5, 7. Разработчики Z80 и SM83 работали на бумаге в восьмеричной системе. Если записать любой байт опкода по основанию 8, он распадается на три восьмеричные цифры (x, y, z), и это как раз битовые поля набора инструкций: x: int = op >> 6 # Bits 7-6: Opcode category (0..3) y: int = (op >> 3) & 7 # Bits 5-3: Destination register or ALU operation (0..7) z: int = op & 7 # Bits 2-0: Source register or condition code (0..7) sourcecraft.dev У всех 64 инструкций LD r, r' (0x40..0x7F) x == 1, поэтому они укладываются в пять строк Viper: if x == 1: 0x40..0x7F: LD r[y], r[z] or HALT (0x76) if op == 0x76: halted = 1 else: vr1: int = 0 if z == 6: hl1: int = (int(mem[0x14504]) << 8) | int(mem[0x14505]) vr1 = read_memory(hl1) else: vr1 = int(mem[0x14500 + z]) if y == 6: write_memory((int(mem[0x14504]) << 8) | int(mem[0x14505]), vr1) else: mem[0x14500 + y] = vr1 sourcecraft.dev Одна проверка покрывает шестьдесят четыре опкода, а y и z выбирают регистр-приёмник и регистр-источник. При x == 2 те же битовые поля задают все восемь операций АЛУ над A и r[z] (ADD, ADC, SUB, SBC, AND, XOR, OR, CP): ещё шестьдесят четыре арифметические инструкции в одном блоке. 256 битовых операций с префиксом 0xCB делятся так же: cb_x == 1 — это BIT, 2 — RES, 3 — SET, а 0 — сдвиг, циклический сдвиг или обмен тетрад y над r[z]. Пятьдесят строк битовой арифметики заменили сотни ветвлений. Четыре строки арифметики указателей вместо ветвлений по адресу На NES можно было схитрить. ОЗУ, PPU, APU, PRG-ROM: всё лежит там, куда его припаяли, поэтому чтение сводится к проверке адреса, и готово. На Game Boy так не выйдет. Процессор по-прежнему видит 64 КБ, но картридж постоянно меняет то, что находится за этим окном: $0000..$3FFF: 16 КБ фиксированного банка ROM 0; $4000..$7FFF: 16 КБ переключаемого банка ROM (до 125/128/512 банков у MBC1/MBC3/MBC5); $A000..$BFFF: 8 КБ внешней SRAM (4 банка); $C000..$CFFF: 4 КБ фиксированного банка рабочей памяти WRAM 0; $D000..$DFFF: 4 КБ переключаемой WRAM (банки 1–7 через SVBK по адресу $FF70); $E000..$FDFF: эхо-область, зеркало $C000..$DDFF. Первая версия проверяла адрес при каждом обращении: если он в этом диапазоне, делаем одно, если в том — другое: if addr < 0x8000: ... elif addr < 0xA000: ... elif addr < 0xC000: ... elif addr < 0xD000: ... elif addr < 0xE000: ... sourcecraft.dev Читается легко и совпадает с тем, как карту памяти рисуют во всех документах. Но Game Boy работает на 4,19 МГц, а GBC в режиме двойной скорости вдвое быстрее, так что эта проверка выполняется миллионы раз в секунду. Мы снова упираемся в ограничения скромного железа. Каждый if — это ветвление, которое Cortex-M33 должен предсказать, а промах останавливает конвейер. Хитрость в том, что любой адрес Game Boy 16-битный, то есть четыре шестнадцатеричные цифры вроде $D123. В двоичном виде это 1101 0001 0010 0011: левые четыре бита (15–12) — старшая тетрада, правые двенадцать (11–0) — смещение внутри страницы размером 4 КБ. Страница в 4 КБ — это 4096 = 2¹² байт, поэтому сдвиг вправо на 12 (addr >> 12) отбрасывает младшие двенадцать бит и оставляет только старшую тетраду: от 0 до 15. Шестнадцать значений, шестнадцать страниц, ровно 64 КБ. Маска в обратную сторону (addr & 0xFFF) оставляет младшие двенадцать бит, то есть смещение 0–4095 внутри страницы. $D123 → 0xD (страница 13) + 0x123 (смещение 291). Старшая тетрада сама говорит, какой банк использовать, никакой if не нужен. Я держу таблицу страниц из 16 записей в self.st (ячейки 32–47 массива array('i', [0]*64)) с заранее вычисленными смещениями внутри self.mem и индексирую её прямо этой тетрадой: Address Range Page Slot Mapped Arena Region $8000..$8FFF st[40] ──► 0x0000 (VRAM Bank 0 or 1, low) $9000..$9FFF st[41] ──► 0x1000 (VRAM Bank 0 or 1, high) $A000..$AFFF st[42] ──► 0xC000 + (sram_bank << 13) $B000..$BFFF st[43] ──► 0xD000 + (sram_bank << 13) $C000..$CFFF st[44] ──► 0x4000 (WRAM Bank 0) $D000..$DFFF st[45] ──► 0x4000 + (wram_bank << 12) $E000..$EFFF st[46] ──► 0x4000 (Echo WRAM0) sourcecraft.dev Переключение банка — одна запись, без копирования: Switching GBC WRAM bank (SVBK at $FF70) wb: int = vw & 7 if wb == 0: wb = 1 st[REG_WRAM_BANK] = wb st[45] = 0x4000 + (wb << 12) # Slot 45 points to the active 4KB WRAM bank sourcecraft.dev А чтение — четыре строки без единого ветвления: 4KB Page Table lookup in Viper page_offset: int = st[32 + (addr >> 12)] val: int = int(mem[page_offset + (addr & 0xFFF)]) sourcecraft.dev Найти в таблице, наложить маску, сложить, загрузить. После этого переключение банков пропало из профилей. Ленивая загрузка двухмегабайтных картриджей по шине QSPI на 115 МГц Картриджи NES из нашей коллекции весили от 40 до 256 КБ, их можно было целиком прочитать в ОЗУ при загрузке. Картриджи Game Boy Color намного больше: Link’s Awakening DX занимает 1 МБ (64 банка по 16 КБ), а Pokémon Crystal — 2 МБ (128 банков). Чтение 2 МБ с QSPI Flash при запуске подвешивает бейдж на несколько секунд. Когда мы разогнали RP2350 через machine.freq(300_000_000), чтобы выиграть запас на кадр, бейдж намертво зависал при переключении банков. Вместе с ним отваливался последовательный порт по USB, и вернуть MonaOS удавалось только передёргиванием питания. Узким местом оказалась общая шина QMI: RP2350 Microcontroller ┌──────────────────────┐ │ Cortex-M33 Cores │ │ 520 KB SRAM │ └──────────┬───────────┘ │ QMI Bus (clk_sys / 2) ┌───────────────┴───────────────┐ │ │ XIP_CS0 (Flash) XIP_CS1 (PSRAM) ┌──────────────────────┐ ┌──────────────────────┐ │ 16 MB QSPI Flash │ │ 8 MB QSPI PSRAM │ │ (Firmware & ROMs) │ │ (Heap & Buffers) │ └──────────────────────┘ └──────────────────────┘ sourcecraft.dev Штатная частота RP2350 — 150 МГц, а прошивка бейджа гоняет его на 230 МГц (разгон на 53%). Судя по схеме бейджа и конфигурации платы tufty2350 от Pimoroni, 16 МБ Flash Winbond W25Q128JVPIQ и 8 МБ PSRAM AP Memory APS6404L-3SQR-ZR (PSRAM_CS на GPIO8) делят линии QSPI_SD0..3 и QSPI_SCLK при PICO_FLASH_SPI_CLKDIV = 2 (clk_sys / 2). На 230 МГц QSPI работает на частоте: Обе микросхемы памяти рассчитаны максимум на 133 МГц (в pimoroni_tufty2350.h указано 266 MHz как «абсолютный максимум, после которого придётся снижать частоту PSRAM»), так что у 115 МГц хороший запас по таймингам. На 300 МГц QSPI выходил на 150 МГц, за пределы паспортных 133 МГц обеих микросхем. Ядро Cortex-M33 это переживало, но пакетное копирование банков по 16 КБ из Flash (XIP_CS0) в PSRAM (XIP_CS1) по общей шине QMI вешало железо. На бейдже 8 МБ PSRAM отданы под кучу MicroPython (gc.mem_free() показывает 8,189,632 свободных байт), поэтому ни вытеснять банки, ни разгонять шину не пришлось: оставить штатные 230 МГц, чтобы шина QMI работала на 115 МГц; один раз выделить в PSRAM область под весь картридж (self.rom = bytearray(self.num_banks * 16384)) с direct_rom = True и откатываться на кольцевой буфер из 20 ячеек, только если вылетит MemoryError; при запуске загружать только банки 0 и 1, чтобы игра стартовала сразу, а каждый банк по 16 КБ подтягивать при первом обращении (self.mem[0x14300 + bank] = slot) и держать в PSRAM до конца сеанса. Это убрало и многосекундную паузу при загрузке, и дёрганье Flash посреди игры. Масштаб 1,5× Экран Game Boy — 160×144, экран бейджа — 320×240. Для удвоения места мало, но 1,5× (240×216, с повтором каждой второй строки по схеме 2:1:2:1) влезает, и это казалось неплохим компромиссом. На экране выглядит терпимо. Часть линий становится вдвое толще, часть остаётся прежней. Зато картинка занимает почти всю высоту экрана (216 из 240 пикселей. — Прим. пер.), хотя выглядит не так, как задумано в игре. Масштабирование я оставил, но по умолчанию включил родной 1:1: 160×144 по центру экрана 320×240, один пиксель ЖК-экрана на один пиксель бейджа, и поле вокруг пошире. 320 px (Badge Screen Width) ┌──────────────────────────────────────────────┐ │ GUTTER (80 px) 160x144 LCD GUTTER (80px)│ │ ┌──────────────┬──────────────┬────────────┐ │ 48 px Top │ │ spf13 labs │ │ │ │ │ │ 60 fps │ 1:1 NATIVE │ [SAV] │ │ │ │ │ PIXEL │ │ │ 144 px LCD │ │ [D-PAD HUD] │ │ │ │ │ │ (Active) │ │ │ │ │ └──────────────┴──────────────┴────────────┘ │ 48 px Bottom │ GAME BOY COLOR │ └──────────────────────────────────────────────┘ sourcecraft.dev В режиме 1:1 пиксель-арт выглядит так, как задумали художники, но, возможно, разглядеть его получится только в очках. Вспоминается старая лупа для Game Boy, обычное увеличительное стекло, которое крепилось над экраном. Может, кто-нибудь сделает такую для бейджа :) Joyplus Handy Boy — лупа для оригинального Game Boy, одна из нескольких накладных линз, которые продавались в 90-х Joyplus Handy Boy с лупой и стереодинамиками. Фото: Thomas Bresson, CC BY 3.0 Если отцентровать окно 160×144, по бокам остаются поля по 80 пикселей, а сверху и снизу по 48. Пустое место рядом с запущенной игрой выглядит как ошибка, да и у настоящего Game Boy вокруг экрана пластик, поэтому я нарисовал рамку: сумеречно-серый фон, тонкие золотые полосы и кремовая надпись GAME BOY COLOR внизу (для монохромных картриджей .gb она меняется на GAME BOY POCKET). На левом поле — небольшая панель с зарядом батареи, частотой кадров и живой подсветкой сенсорной крестовины и кнопок, на правом — индикаторы сохранения состояния SAV и RES. Link’s Awakening DX Link's Awakening DX в режиме 1:1 на бейдже GitHub Universe 2026 Pokémon Crystal Pokémon Crystal в режиме 1:1 на бейдже GitHub Universe 2026 Super Mario Land Super Mario Land в режиме 1:1 на бейдже GitHub Universe 2026 Tetris DX Tetris DX в режиме 1:1 на бейдже GitHub Universe 2026 С ROM-ами для GBC всё ещё хитрее Железо прожило очень долго. Монохромный Game Boy вышел в Японии 21 апреля 1989 года, а версия Color, в которой частоту SM83 удвоили до 8,4 МГц, появилась только 21 октября 1998 года, через девять лет, и с тем же видеочипом на 160×144. Nintendo выпускала семейство GB/GBC до марта 2003 года. К концу этого срока неиспробованных регистров не осталось, и поздние игры для GBC выжимают из железа всё, что оно позволяет: от включения слоя окна посреди кадра до анимированных шрифтов, которые подгружаются прямо из ROM. Окно, которое делит экран, надо фиксировать построчно В Oracle of Ages, когда подходишь к персонажу, внизу появляется окно диалога, и спрайты мира рисовались прямо поверх текста. Чтобы нарисовать окно диалога внизу экрана (LY = 80..143), игра включает слой Window (бит 5 регистра LCDC) по совпадению LYC == LY на строке 80 и выключает его снова во время VBlank. Мой первый рендерер проверял один WY на весь кадр уже после строки 143 и судил обо всех 144 строках по тому состоянию регистров, которое было в конце кадра. В итоге передвигаемые камни на строках 0..79 вели себя так, будто их закрывает окно, а спрайты на строках 80..143 рисовались поверх текста, потому что VBlank уже сбросил бит 5 LCDC. Если на каждой строке сохранять LCDC, SCY, SCX, WX и WY в 0x14600 и 0x14840, а во время отрисовки отслеживать текущую строку окна в 0x14900, рендерер получает ровно то, что видел видеочип на этой строке: Snapshot per-scanline LCDC, SCY, SCX, WX, WY for visible lines 0..143 if sl < 144: sl_off: int = 0x14600 + (sl << 2) mem[sl_off] = mem[0x14140] # LCDC mem[sl_off + 1] = mem[0x14142] # SCY mem[sl_off + 2] = mem[0x14143] # SCX mem[sl_off + 3] = mem[0x1414B] # WX mem[0x14840 + sl] = mem[0x1414A] # WY sourcecraft.dev Двойная скорость и бюджет строки В Link’s Awakening DX глюк был страннее: двухтайловая анимация ходьбы Линка на каждом шаге на один кадр выворачивалась наизнанку, но только при ходьбе вниз, а влево и вправо — никогда. При ходьбе влево или вправо два спрайта Линка размером 8×16 остаются на месте. При ходьбе вниз каждые 8 кадров игра меняет их тайлы в VRAM ($8000/$8020) и переключает hflip (0x20) у обеих записей OAM ($FE0B/$FE0F). Link’s Awakening DX работает в режиме двойной скорости GBC (бит 7 регистра KEY1), поэтому на одну строку развёртки процессору положено 228 M-циклов вместо обычных 114. С бюджетом в 114 строка обрывалась ровно между записью тайла в VRAM и отражением в OAM, и Линк на кадр оставался развёрнутым наполовину: target_cyc: int = 228 if st[REG_DOUBLE_SPD] else 114 sourcecraft.dev Когда режим двойной скорости получил свои полные 228 циклов на строку, разрыв исчез. Указатель стека может смотреть в ROM Когда я запустил Pokémon Crystal, вступление профессора Оука и все рамки меню показывались пустыми прямоугольниками. Я и не знал, что железо позволяет то, что здесь делает игра. Чтобы распаковать однобитные тайлы шрифта и рамок в двухбитный формат в WRAM, Pokémon Crystal вызывает FarCopyBytesDouble_DoubleBankSwitch ($0DEF). Эта процедура направляет SP в переключаемый банк ROM ($4000..$7FFF), в цикле делает POP DE, вытаскивая по два байта каждые 3 M-цикла, передаёт результат через HDMA во время HBlank ($4209) и останавливает передачу командой RES 7, (HL) по адресу $FF55 (424A: cb be). Я исходил из того, что SP всегда указывает в ОЗУ, а RES 7 — обычная битовая операция, и оба шага ломались. Когда POP rr при SP < 0x8000 стал читать через окно ROM, а сброс бита 7 в $FF55 стал трактоваться как отмена HDMA (а не как GP-DMA на 128 тайлов 0x7F), Оук и рамки вернулись. @micropython.viper def update_palettes_cgb_16(st: ptr32, mem: ptr8, fpal: ptr16): st[REG_PAL_DIRTY] = 0 for i in range(32): i2: int = i << 1 bgr: int = int(mem[0x14200 + i2]) | (int(mem[0x14201 + i2]) << 8) r5: int = bgr & 0x1F g5: int = (bgr >> 5) & 0x1F b5: int = (bgr >> 10) & 0x1F col_bg: int = (r5 << 11) | (g5 << 6) | b5 if i & 3: col_bg = col_bg | 0x0020 fpal[i] = col_bg sourcecraft.dev Вместе с рендерером фона, который пропускает пустые тайлы, отрисовка кадра по нашим замерам через последовательный порт занимает примерно от 1,5 до 2,8 мс. РПГ на шнурке для конференц-коридоров По нашим замерам на бейдже, выполнение кода процессора укладывается в 12 мс, отрисовка — в 3 мс, и цикл помещается в бюджет 16,6 мс, нужный для 60 Гц. Сохранения тоже должны работать: это всё-таки бейдж на конференции. Если удерживать A + B или START + SELECT 650 мс (now - self.menu_hold_start >= 650 в apps/gbc/init.py; есть ещё таймер AUTO_SAVE_IDLE_MS на 60 секунд, если кнопки не нажимают), состояние сохраняется и открывается меню паузы с пропуском кадров, фильтрами строк развёртки, масштабом и выходом. Касание сенсорной площадки HOME на обороте вызывает machine.Pin.board.BUTTON_HOME.irq, а тот — save_state(sync_sram=True): область памяти на 84 КБ и состояние регистров записываются во Flash перед возвратом в MonaOS. Код открыт: spf13/universe-2026-badge-hacks. Чтобы поставить его на бейдж: подключите бейдж по USB, откройте в MonaOS USB Disk и смонтируйте диск; склонируйте репозиторий и скопируйте приложение: git clone spf13/universe-2026-badge-hacks cd universe-2026-badge-hacks Copy-Item -Recurse -Force .\apps\gbc F:\apps\ sourcecraft.dev положите в F:\apps\gbc\roms\ свои законно снятые дампы .gb/.gbc (защищённые авторским правом ROM в репозитории не распространяются): zelda_ladx.gbc (Link’s Awakening DX) pokemon_crystal.gbc (Pokémon Crystal) dw_1_2.gbc (Dragon Warrior I & II) tetris_dx.gbc (Tetris DX) zelda_ages.gbc (Oracle of Ages) mario_land.gb (Super Mario Land) ff_legend.gb (The Final Fantasy Legend) безопасно извлеките диск, откройте лаунчер GBC, переверните бейдж вверх ногами и играйте. Работа над эмулятором Game Boy Color заодно ускорила и эмулятор NES. Когда пять приёмов Viper заработали на SM83, я перенёс их обратно в apps/nes/emu.py: переключение банков CHR через указатели (REG_CHR_B0_OFF / REG_CHR_B1_OFF внутри self.mem вместо копирования 8192 байт в Python при каждом переключении); все 262 строки развёртки внутри одного вызова Viper вместо выхода по REG_CHR_DIRTY; обновление палитры в Viper по флагу изменений (REG_PAL_DIRTY); заранее вычисленные указатели на строки таблицы имён с развёрнутой записью по 8 пикселей в render_bg_32; более короткие быстрые пути для операндов и циклов ожидания. Теперь у меня на шее висит Game Boy Color, на котором в режиме 1:1 идут Link’s Awakening DX и Pokémon Crystal. Если будете на Universe в Сан-Франциско, подходите поздороваться.

  4. Declarative Go CLIs with Commandment Over the last seven years in IT consulting, I have built more than 50 CLIs for customers and projects. I spent a lot of that time refining workflows around Cobra and Viper, trying to make CLI authoring feel as clean and idiomatic as the rest of the Go around it. I never quite got the workflow I wanted. There was no single breaking point. The same kinds of friction just kept showing up. I wanted flags and arguments to become ordinary Go values once they reached the application. I got tired of defining the same idea again because help, completion, configuration, or tests needed it. I wanted new capabilities to fit the CLI instead of feeling bolted on. Setup order should only matter when order is actually part of the CLI's meaning. I also spend a lot of time with Kubernetes and Terraform, so declarative systems were already a natural way for me to think. You declare relationships, validate them, and let the system derive the consequences. After years of trying to improve my CLI workflow, I stopped thinking the remaining friction was another convention I had failed to discover. I thought the underlying authoring model was the constraint. That line of thinking became Commandment, a declarative CLI framework for Go. Meet alienctl I'll use a small fictional CLI called alienctl throughout the article. It has two commands. $ alienctl scan mars scanning mars $ ALIEN_BEAM_STRENGTH=2 alienctl abduct --beam-strength 4 cow abducting cow with beam strength 4 BeamStrength has a static default of 1. The host environment can contribute 2 through ALIEN_BEAM_STRENGTH. The user can contribute 4 through --beam-strength. The accepted value must also be between 1 and 10. That one value captures the broader problem I kept running into. The flag spelling can live in parser setup, help and completion can need their own description of it, configuration can separately decide whether the flag beats the environment, and tests can encode the same precedence again. Each piece can be reasonable on its own while the same fact ends up with several owners. Commandment takes a different approach. Application code declares semantic relationships in ordinary Go. Compile validates them and produces an immutable Application, and later operations read from that application instead of rebuilding the CLI's meaning. That's what I mean by declarative here. It does not mean YAML or struct tags, and it does not replace ordinary Go control flow. Definition -> Compile -> immutable Application type abductConfig struct { Target string BeamStrength int } abductCmd := cli.Command[abductConfig]{ Name: "abduct", Declare: func(cb *cli.CommandBuilder[abductConfig]) { cb.Arguments.String(&cb.Config.Target, "target") beamStrength := cb.Values.Int(&cb.Config.BeamStrength) cb.Values.Default(beamStrength, 1) cb.Values.Environment(beamStrength, "ALIEN_BEAM_STRENGTH") cb.Flags.ValueFor(beamStrength).Long("beam-strength") cb.Rule.Between(beamStrength, 1, 10) }, Run: func(_ context.Context, cfg *abductConfig) error { fmt.Printf( "abducting %s with beam strength %d\n", cfg.Target, cfg.BeamStrength, ) return nil }, } The root also declares a simpler scan command. type scanConfig struct { World string } var definition = cli.Definition[struct{}]{ Name: "alienctl", Declare: func(cb *cli.CommandBuilder[struct{}]) { scanCmd := cli.Command[scanConfig]{ Name: "scan", Declare: func(cb *cli.CommandBuilder[scanConfig]) { cb.Arguments.String(&cb.Config.World, "world") }, Run: func(_ context.Context, cfg *scanConfig) error { fmt.Printf("scanning %s\n", cfg.World) return nil }, } cb.Subcommands.Command(scanCmd) cb.Subcommands.Command(abductCmd) }, } The separate scanConfig and abductConfig types are deliberate. Each command owns the Go state its handler actually needs instead of contributing fields to one universal root configuration. Commandment's declarations stay ordinary, statically typed Go. The design does not depend on reflection-driven struct or tag decoding. The process entrypoint is ordinary Go too. app, err := cli.Compile(definition) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := app.RunFromProcess(context.Background()); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(cli.ExitCode(err)) } For that invocation, the same destination has three candidate values. static default -> 1 environment -> 2 flag -> 4 resolved value -> 4 The handler never sees a parser object or a bag of raw strings. It gets an ordinary int. That was one of the things I wanted from the start. The CLI boundary is textual, but application code should work with typed Go values. int is only the built-in case. An application-defined Go type can use a ValueCodec[T] to define how it crosses the textual CLI boundary. Flags, environment input, defaults, resolution, and inspection can all work with that typed destination instead of inventing separate string representations. The default, environment variable, flag, and range rule all point at the same typed destination. There is no second BeamStrength definition for configuration or validation. Help and completion use the compiled application The compiled application already has enough information to render help. $ ./alienctl --help Usage: alienctl [flags] <command> Commands: scan abduct help Show help. completion Generate shell completion source Flags: --help Show help. -h Show help. The abduct command is available through the intrinsic help action as well. $ ./alienctl help abduct Usage: alienctl abduct [flags] <target> Arguments: <target> Flags: --beam-strength VALUE, --beam-strength=VALUE I did not define a second command-and-flag model for help. The compiled application already knows the command, positional argument, and flag spelling, so help can present them without another description of the CLI. Completion uses the same grammar. With incomplete input ab, the application can determine what can legally come next. completion, err := app.Complete(ctx, cli.CompletionRequest{ Args: []string{"ab"}, Cursor: cli.CompletionCursor{ Argument: 0, Byte: 2, }, }) For this application, the completion result contains abduct. abduct The completion request is not tied to a shell. Shell integration adapts the semantic result for a concrete client without defining another command language. The compiled application still has the grammar, so execution, help, and completion all use it. Cobra already does this part well If you use Cobra, this part should be familiar. Cobra already gives Go applications an executable command model with arguments and flags, generated help, and shell completion. Viper can sit alongside it as a configuration registry, binding command-line flags and environment variables and resolving multiple configuration sources with an explicit precedence order. In the example above, Cobra + Viper can also resolve the effective value to 4. Commandment is not a feature-for-feature replacement for Viper. Its boundary is the CLI's semantic model. Broader application configuration can stay in ordinary application code. When external configuration affects CLI semantics, it crosses that boundary as typed input instead of becoming another model of the CLI. What pushed me toward Commandment was the authoring model. After years of writing CLIs, I was tired of carrying setup knowledge across declarations, follow-up mutations, bindings, lifecycle hooks, and initialization timing. Cobra and Viper can be wrapped and organized carefully. I wanted the relationships themselves to be the source of truth. Commandment validates those relationships during compilation. Order affects behavior only when order is part of the model. Dependencies between semantic values are declared too, so Commandment can validate scope and cycles and derive evaluation order from the dependency graph instead of callback timing. A typical Cobra + Viper arrangement separates those responsibilities roughly like this. Cobra / pflag command grammar flags help completion Viper configuration sources precedence effective configuration application code application-specific policy versus Commandment BeamStrength destination <- default 1 <- environment ALIEN_BEAM_STRENGTH <- flag --beam-strength <- rule Between(1, 10) Compile | v immutable Application | +--------+--------+ | | | Run Inspect Complete | semantic tests Both approaches can produce 4. With Commandment, the application still knows why 4 won. Inspecting why the flag won $ ALIEN_BEAM_STRENGTH=2 alienctl abduct --beam-strength 4 cow abducting cow with beam strength 4 A terminal-output test can prove that the program printed 4, but it cannot distinguish normal flag precedence from an ignored environment value, a handler overwrite, or a fallback that happened to produce the same integer. Because Commandment retained the invocation semantics, Inspect can analyze explicit invocation input without executing the selected handler. The clitest package can assert those observations directly. func TestBeamStrengthFlagWins(t *testing.T) { t.Parallel() app := clitest.Compile(t, definition) beamStrength := clitest.Command("abduct").Flag("--beam-strength").Value() request := cli.InspectionRequest{ Env: cli.Env{{ Name: "ALIEN_BEAM_STRENGTH", Value: "2", }}, Args: []string{"abduct", "--beam-strength", "4", "cow"}, } clitest.Inspect(t.Context(), app, request).Require(t, clitest.InspectionReady(), beamStrength.Text("4"), beamStrength.ContributedBy(cli.ValueProducerKindFlag), ) } That test proves both the effective value and the winning producer. effective value = 4 winning producer = flag The default, environment input, and flag are three producers for one semantic destination. Resolution chooses the effective contribution and retains its provenance. The test does not recreate Commandment's precedence rules. It asks the compiled application what happened. Parsing does not erase the reason behind the result. Inspect can explain it later without running the handler or inferring semantics from presentation text. One semantic authority does not mean one representation One semantic authority does not require one giant data structure or one implementation path for everything. Help, completion, inspection, diagnostics, schema, reference data, and runtime value state have different consumers and different lifetimes. They deserve different representations. A semantic fact should still have one authority. Other operations and artifacts can project that fact for their own purpose, but they should not silently redefine it. Definition | | Compile v immutable Application | +-- Run / RunFromProcess --> execution and intrinsic actions such as help +-- Complete -----------> semantic completion +-- Inspect ------------> invocation-specific observation `-- Schema -------------> detached static artifact Execution, help, completion, inspection, and schema need different representations, but they should agree on the command and value semantics they share. That is the design I had been trying to get to. Handlers receive typed Go values, each CLI fact has one owner, and help, completion, inspection, and tests reuse the compiled model. Setup order only matters when the model says it matters. When would I use this instead of Cobra? Cobra fits well when the main job is an executable command tree with commands, arguments, flags, dispatch, help, and completion. Pairing it with Viper can also provide configuration through environment variables, defaults, files, and explicit precedence. Commandment is aimed at CLIs where the command tree is only part of the problem. Typed resolution, provenance, and policy may also need to stay coherent across execution, completion, diagnostics, tooling, and tests. Cobra can implement the behavior shown in this article. The decision is whether a command tree plus configuration registry is enough semantic authority for the CLI you are building. For a CLI dominated by routing, flags, help, and completion, Cobra is probably the smaller choice. Commandment starts to earn its extra machinery when you need to ask the compiled CLI why a value resolved the way it did, project the same accepted semantics into tooling, or test those semantics without recreating them. At that point, I would rather have one source of CLI meaning feeding several views than several reasonable systems that can slowly drift apart. Commandment RC1 Commandment is now in its RC1 review period and requires Go 1.27.1. I am using this release-candidate period to get the API in front of people building real Go CLIs before I finalize v1.0.0. The source, examples, and documentation are all in the Commandment repository. If you try Commandment on an existing Go CLI, I'd especially like to hear what gets simpler, what stays awkward, and anything in the API that you think should change before v1.0.0 is finalized.

  5. YouTube · · YouTube description · Weekend Repos · spf13/cobra

    Cobra: The CLI Framework Behind Kubernetes & Docker The Go framework powering kubectl, Docker, and GitHub CLI. Build enterprise Go CLI apps with POSIX flags and subcommands. • Cobra structures complex tools with nested subcommands and flags. • Fully POSIX-compliant flags handle short, long, and cascading options. • Automatic shell completions support Bash, Zsh, Fish, and PowerShell. • Intelligent typo suggestions prevent frustrating command-line mistakes. • Cobra powers Kubernetes, Hugo, GitHub CLI, and the Go ecosystem. Repo: spf13/cobra (spf13/cobra · Apache-2.0) Interactive gallery & weekly developer dispatch (install commands + CLI cheatsheets): berkayturanci.github.io Every repo we've covered: berkayturanci/awesome-weekend-repos Sources: - GitHub — spf13/cobra (github.com/spf13/cobra) - Cobra Official Documentation (cobra.dev) Full link is in the description above. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [ar] Cobra: إطار عمل CLI الذي يدعم Kubernetes وDocker إطار عمل Go الذي يدعم kubectl وDocker وGitHub CLI. أنشئ تطبيقات Go CLI للمؤسسات باستخدام علامات POSIX والأوامر الفرعية. • يُنظّم Cobra الأدوات المعقدة باستخدام أوامر فرعية وعلامات متداخلة. • علامات متوافقة تمامًا مع POSIX تدعم الخيارات القصيرة والطويلة والمتتالية. • إكمال تلقائي للأوامر يدعم Bash وZsh وFish وPowerShell. • اقتراحات ذكية لتصحيح الأخطاء الإملائية تمنع أخطاء سطر الأوامر المُحبطة. • يدعم Cobra كلاً من Kubernetes وHugo وGitHub CLI ونظام Go البيئي. ... المستودع: spf13/cobra (spf13/cobra · Apache-2.0) جميع المستودعات التي غطيناها: berkayturanci/awesome-weekend-repos المصادر: - GitHub — spf13/cobra (github.com/spf13/cobra) - الوثائق الرسمية لـ Cobra (cobra.dev) الرابط الكامل موجود في الوصف أعلاه. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [bn] Cobra: Kubernetes ও Docker-এর নেপথ্যের CLI ফ্রেমওয়ার্ক Go ফ্রেমওয়ার্ক যা kubectl, Docker, এবং GitHub CLI-কে শক্তি জোগায়। POSIX ফ্ল্যাগ এবং সাবকমান্ড ব্যবহার করে এন্টারপ্রাইজ Go CLI অ্যাপ তৈরি করুন। • Cobra নেস্টেড সাবকমান্ড এবং ফ্ল্যাগের মাধ্যমে জটিল টুলগুলোকে কাঠামোবদ্ধ করে। • সম্পূর্ণ POSIX-সম্মত ফ্ল্যাগগুলো শর্ট, লং এবং ক্যাসকেডিং অপশন পরিচালনা করে। • স্বয়ংক্রিয় শেল কমপ্লিশন Bash, Zsh, Fish, এবং PowerShell সমর্থন করে। • ইন্টেলিজেন্ট টাইপো সাজেশন হতাশাজনক কমান্ড-লাইন ভুল প্রতিরোধ করে। • Cobra Kubernetes, Hugo, GitHub CLI, এবং Go ইকোসিস্টেমকে শক্তি জোগায়। রিপো: spf13/cobra (spf13/cobra · Apache-2.0) আমাদের কভার করা প্রতিটি রিপো: berkayturanci/awesome-weekend-repos উৎস: - গিটহাব — spf13/cobra (github.com/spf13/cobra) - কোবরা অফিসিয়াল ডকুমেন্টেশন (cobra.dev) সম্পূর্ণ লিঙ্কটি উপরের বিবরণে দেওয়া আছে। #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [de-DE] Cobra: Das CLI-Framework hinter Kubernetes & Docker Das Go-Framework, das kubectl, Docker und die GitHub-CLI antreibt. Entwickeln Sie Go-CLI-Anwendungen für Unternehmen mit POSIX-Flags und Unterbefehlen. • Cobra strukturiert komplexe Tools mit verschachtelten Unterbefehlen und Flags. • Vollständig POSIX-konforme Flags unterstützen kurze, lange und verschachtelte Optionen. • Automatische Shell-Vervollständigung unterstützt Bash, Zsh, Fish und PowerShell. • Intelligente Tippfehlerkorrekturen verhindern lästige Fehler in der Befehlszeile. • Cobra ist die Basis von Kubernetes, Hugo, der GitHub-CLI und dem Go-Ökosystem. Repository: spf13/cobra (spf13/cobra · Apache-2.0) Alle bisher behandelten Repositories: berkayturanci/awesome-weekend-repos Quellen: - GitHub — spf13/cobra (github.com/spf13/cobra) - Offizielle Cobra-Dokumentation (cobra.dev) Der vollständige Link befindet sich in der obigen Beschreibung. #golang #entwickler #opensource #programmierung #terminal #softwareentwicklung #systemdesign #backend #devtok [es-US] Cobra: El framework CLI detrás de Kubernetes y Docker El framework de Go que impulsa kubectl, Docker y GitHub CLI. Crea aplicaciones empresariales de Go CLI con indicadores y subcomandos POSIX. • Cobra estructura herramientas complejas con subcomandos y indicadores anidados. • Los indicadores totalmente compatibles con POSIX admiten opciones cortas, largas y en cascada. • El autocompletado de comandos es compatible con Bash, Zsh, Fish y PowerShell. • Las sugerencias inteligentes de errores tipográficos evitan errores frustrantes en la línea de comandos. • Cobra impulsa Kubernetes, Hugo, GitHub CLI y el ecosistema de Go. Repositorio: spf13/cobra (spf13/cobra · Apache-2.0) Todos los repositorios que hemos cubierto: berkayturanci/awesome-weekend-repos Fuentes: - GitHub — spf13/cobra (github.com/spf13/cobra) - Documentación oficial de Cobra (cobra.dev) El enlace completo se encuentra en la descripción anterior. #golang #desarrollador #códigoabierto #programación #terminal #ingenieríadesoftware #diseñodesistemas #backend #devtok [fr-FR] Cobra : Le framework CLI derrière Kubernetes et Docker Le framework Go qui alimente kubectl, Docker et l'interface de ligne de commande GitHub. Créez des applications Go CLI d'entreprise avec des options et des sous-commandes POSIX. • Cobra structure les outils complexes avec des sous-commandes et des options imbriquées. • Les options entièrement conformes à la norme POSIX gèrent les options courtes, longues et en cascade. • La complétion automatique des commandes shell prend en charge Bash, Zsh, Fish et PowerShell. • Les suggestions intelligentes de fautes de frappe évitent les erreurs frustrantes en ligne de commande. • Cobra alimente Kubernetes, Hugo, l'interface de ligne de commande GitHub et l'écosystème Go. • Dépôt : spf13/cobra (spf13/cobra · Apache-2.0) Tous les dépôts présentés : berkayturanci/awesome-weekend-repos Sources : - GitHub — spf13/cobra (github.com/spf13/cobra) - Documentation officielle de Cobra (cobra.dev) Lien complet dans la description ci-dessus. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [hi] Cobra: Kubernetes और Docker के पीछे का CLI फ्रेमवर्क kubectl, Docker और GitHub CLI को शक्ति प्रदान करने वाला Go फ्रेमवर्क। POSIX फ्लैग और सबकमांड का उपयोग करके एंटरप्राइज़ Go CLI ऐप्स बनाएं। • कोबरा नेस्टेड सबकमांड और फ्लैग के साथ जटिल टूल को संरचित करता है। • पूरी तरह से POSIX-अनुरूप फ्लैग शॉर्ट, लॉन्ग और कैस्केडिंग विकल्पों को संभालते हैं। • स्वचालित शेल पूर्णता Bash, Zsh, Fish और PowerShell का समर्थन करती है। • बुद्धिमान टाइपो सुझाव कमांड-लाइन की गलतियों से बचाते हैं। • कोबरा Kubernetes, Hugo, GitHub CLI और Go इकोसिस्टम को शक्ति प्रदान करता है। रिपॉजिटरी: spf13/cobra (spf13/cobra · Apache-2.0) हमारे द्वारा कवर की गई सभी रिपॉजिटरी: berkayturanci/awesome-weekend-repos स्रोत: - GitHub — spf13/cobra (github.com/spf13/cobra) - कोबरा आधिकारिक दस्तावेज़ (cobra.dev) पूरा लिंक ऊपर दिए गए विवरण में है। #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [id] Cobra: Framework CLI di Balik Kubernetes & Docker Kerangka kerja Go yang mendukung kubectl, Docker, dan GitHub CLI. Bangun aplikasi Go CLI perusahaan dengan flag dan subperintah POSIX. • Cobra menyusun alat-alat kompleks dengan subperintah dan flag bersarang. • Flag yang sepenuhnya sesuai dengan POSIX menangani opsi pendek, panjang, dan bertingkat. • Penyelesaian shell otomatis mendukung Bash, Zsh, Fish, dan PowerShell. • Saran kesalahan ketik yang cerdas mencegah kesalahan baris perintah yang menjengkelkan. • Cobra mendukung Kubernetes, Hugo, GitHub CLI, dan ekosistem Go. Repositori: spf13/cobra (spf13/cobra · Apache-2.0) Setiap repositori yang telah kami bahas: berkayturanci/awesome-weekend-repos Sumber: - GitHub — spf13/cobra (github.com/spf13/cobra) - Dokumentasi Resmi Cobra (cobra.dev) Tautan lengkap ada di deskripsi di atas. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [it] Cobra: Il framework CLI dietro Kubernetes e Docker Il framework Go alla base di kubectl, Docker e GitHub CLI. Crea applicazioni Go CLI di livello enterprise con flag e sottocomandi POSIX. • Cobra struttura strumenti complessi con sottocomandi e flag annidati. • I flag, pienamente conformi a POSIX, gestiscono opzioni brevi, lunghe e a cascata. • Il completamento automatico della shell supporta Bash, Zsh, Fish e PowerShell. • I suggerimenti intelligenti per la correzione degli errori di battitura prevengono fastidiosi errori da riga di comando. • Cobra alimenta Kubernetes, Hugo, GitHub CLI e l'ecosistema Go. Repository: spf13/cobra (spf13/cobra · Apache-2.0) Tutti i repository che abbiamo trattato: berkayturanci/awesome-weekend-repos Fonti: - GitHub — spf13/cobra (github.com/spf13/cobra) - Documentazione ufficiale di Cobra (cobra.dev) Il link completo è nella descrizione qui sopra. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [iw] Cobra: התשתית ל-CLI מאחורי Kubernetes ו-Docker מסגרת Go המפעילה את kubectl, Docker ו-GitHub CLI. בנה אפליקציות Go CLI ארגוניות עם דגלי POSIX ותתי-פקודות. • Cobra בונה כלים מורכבים עם תת-פקודות ודגלים מקוננים. • דגלים תואמי POSIX מלאים מטפלים באפשרויות קצרות, ארוכות ומדורגות. • השלמות מעטפת אוטומטיות תומכות ב-Bash, Zsh, Fish ו-PowerShell. • הצעות חכמות לשגיאות הקלדה מונעות טעויות מתסכלות בשורת הפקודה. • Cobra מפעילה את Kubernetes, Hugo, GitHub CLI ואת מערכת האקולוגית של Go. מאגר: spf13/cobra (spf13/cobra · Apache-2.0) כל מאגר שסקרנו: berkayturanci/awesome-weekend-repos מקורות: - GitHub — spf13/cobra (github.com/spf13/cobra) - התיעוד הרשמי של Cobra (cobra.dev) הקישור המלא נמצא בתיאור למעלה. #golang #מפתח #קוד פתוח #קידוד #טרמינל #הנדסת תוכנה #עיצוב מערכת #backend #devtok [ja] Cobra:KubernetesとDockerを支えるCLIフレームワーク kubectl、Docker、GitHub CLIを支えるGoフレームワーク。 POSIXフラグとサブコマンドを使用して、エンタープライズ向けGo CLIアプリケーションを構築できます。 • Cobraは、ネストされたサブコマンドとフラグを用いて複雑なツールを構造化します。 • POSIXに完全準拠したフラグは、短いオプション、長いオプション、カスケードオプションに対応します。 • 自動シェル補完は、Bash、Zsh、Fish、PowerShellをサポートします。 • インテリジェントなタイプミス予測機能により、煩わしいコマンドライン入力ミスを防ぎます。 • Cobraは、Kubernetes、Hugo、GitHub CLI、そしてGoエコシステムを支えています。 リポジトリ: spf13/cobra (spf13/cobra · Apache-2.0) これまで取り上げたすべてのリポジトリ: berkayturanci/awesome-weekend-repos 情報源: - GitHub — spf13/cobra (github.com/spf13/cobra) - Cobra 公式ドキュメント (cobra.dev) 完全なリンクは上記の説明に記載されています。 #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [ko] Cobra: 쿠버네티스와 도커를 지탱하는 CLI 프레임워크 kubectl, Docker, GitHub CLI를 지원하는 Go 프레임워크입니다. POSIX 플래그와 서브 명령어를 사용하여 엔터프라이즈급 Go CLI 애플리케이션을 구축하세요. • Cobra는 중첩된 서브 명령어와 플래그를 통해 복잡한 도구를 구조화합니다. • 완벽한 POSIX 규격을 준수하는 플래그는 짧은 옵션, 긴 옵션, 계단식 옵션을 모두 지원합니다. • Bash, Zsh, Fish, PowerShell을 지원하는 자동 셸 완성 기능을 제공합니다. • 지능형 오타 수정 기능으로 명령줄 오류를 방지합니다. • Cobra는 Kubernetes, Hugo, GitHub CLI 및 Go 생태계를 지원합니다. 저장소: spf13/cobra (spf13/cobra · Apache-2.0) 다룬 모든 저장소: berkayturanci/awesome-weekend-repos 참고 자료: - GitHub — spf13/cobra (github.com/spf13/cobra) - Cobra 공식 문서 (cobra.dev) 전체 링크는 위 설명에 있습니다. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [ml] Cobra: Kubernetes-നും Docker-നും പിന്നിലെ CLI ഫ്രെയിംവർക്ക് kubectl, Docker, GitHub CLI എന്നിവയ്ക്ക് ശക്തി പകരുന്ന Go ഫ്രെയിംവർക്ക്. POSIX ഫ്ലാഗുകളും സബ് കമാൻഡുകളും ഉപയോഗിച്ച് എന്റർപ്രൈസ് Go CLI ആപ്പുകൾ നിർമ്മിക്കുന്നു. • നെസ്റ്റഡ് സബ് കമാൻഡുകളും ഫ്ലാഗുകളും ഉപയോഗിച്ച് സങ്കീർണ്ണമായ ഉപകരണങ്ങൾ കോബ്ര നിർമ്മിക്കുന്നു. • പൂർണ്ണമായും POSIX-അനുയോജ്യമായ ഫ്ലാഗുകൾ ഷോർട്ട്, ലോംഗ്, കാസ്കേഡിംഗ് ഓപ്ഷനുകൾ കൈകാര്യം ചെയ്യുന്നു. • ഓട്ടോമാറ്റിക് ഷെൽ പൂർത്തീകരണങ്ങൾ Bash, Zsh, Fish, PowerShell എന്നിവയെ പിന്തുണയ്ക്കുന്നു. • ബുദ്ധിപരമായ അക്ഷരത്തെറ്റ് നിർദ്ദേശങ്ങൾ നിരാശാജനകമായ കമാൻഡ്-ലൈൻ തെറ്റുകൾ തടയുന്നു. • കോബ്ര കുബർനെറ്റസ്, ഹ്യൂഗോ, GitHub CLI, Go ഇക്കോസിസ്റ്റം എന്നിവയ്ക്ക് ശക്തി പകരുന്നു. റെപ്പോ: spf13/cobra (spf13/cobra · Apache-2.0) ഞങ്ങൾ ഉൾപ്പെടുത്തിയ എല്ലാ റെപ്പോകളും: berkayturanci/awesome-weekend-repos ഉറവിടങ്ങൾ: - GitHub — spf13/cobra (github.com/spf13/cobra) - കോബ്രയുടെ ഔദ്യോഗിക ഡോക്യുമെന്റേഷൻ (cobra.dev) പൂർണ്ണ ലിങ്ക് മുകളിലുള്ള വിവരണത്തിലാണ്. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [nl-NL] Cobra: Het CLI-framework achter Kubernetes & Docker Het Go-framework dat de basis vormt voor kubectl, Docker en GitHub CLI. Bouw bedrijfsapplicaties met Go CLI en POSIX-vlaggen en subopdrachten. • Cobra structureert complexe tools met geneste subopdrachten en vlaggen. • Volledig POSIX-compatibele vlaggen ondersteunen korte, lange en trapsgewijze opties. • Automatische shell-aanvulling ondersteunt Bash, Zsh, Fish en PowerShell. • Intelligente suggesties voor typefouten voorkomen frustrerende fouten in de commandoregel. • Cobra vormt de basis voor Kubernetes, Hugo, GitHub CLI en het Go-ecosysteem. Repository: spf13/cobra (spf13/cobra · Apache-2.0) Alle repositories die we hebben behandeld: berkayturanci/awesome-weekend-repos Bronnen: - GitHub — spf13/cobra (github.com/spf13/cobra) - Officiële Cobra-documentatie (cobra.dev) De volledige link staat in de beschrijving hierboven. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [pa] Cobra: ਕੁਬਰਨੇਟਸ (Kubernetes) ਅਤੇ ਡੌਕਰ (Docker) ਦੇ ਪਿੱਛੇ ਦਾ CLI ਫਰੇਮਵਰਕ ਗੋ ਫਰੇਮਵਰਕ kubectl, Docker, ਅਤੇ GitHub CLI ਨੂੰ ਪਾਵਰ ਦਿੰਦਾ ਹੈ। POSIX ਫਲੈਗ ਅਤੇ ਸਬਕਮਾਂਡ ਨਾਲ ਐਂਟਰਪ੍ਰਾਈਜ਼ Go CLI ਐਪਸ ਬਣਾਓ। • ਕੋਬਰਾ ਨੇਸਟਡ ਸਬਕਮਾਂਡ ਅਤੇ ਫਲੈਗ ਨਾਲ ਗੁੰਝਲਦਾਰ ਟੂਲ ਬਣਾਉਂਦਾ ਹੈ। • ਪੂਰੀ ਤਰ੍ਹਾਂ POSIX-ਅਨੁਕੂਲ ਫਲੈਗ ਛੋਟੇ, ਲੰਬੇ ਅਤੇ ਕੈਸਕੇਡਿੰਗ ਵਿਕਲਪਾਂ ਨੂੰ ਸੰਭਾਲਦੇ ਹਨ। • ਆਟੋਮੈਟਿਕ ਸ਼ੈੱਲ ਸੰਪੂਰਨਤਾ Bash, Zsh, Fish, ਅਤੇ PowerShell ਦਾ ਸਮਰਥਨ ਕਰਦੇ ਹਨ। • ਬੁੱਧੀਮਾਨ ਟਾਈਪੋ ਸੁਝਾਅ ਨਿਰਾਸ਼ਾਜਨਕ ਕਮਾਂਡ-ਲਾਈਨ ਗਲਤੀਆਂ ਨੂੰ ਰੋਕਦੇ ਹਨ। • ਕੋਬਰਾ Kubernetes, Hugo, GitHub CLI, ਅਤੇ Go ਈਕੋਸਿਸਟਮ ਨੂੰ ਪਾਵਰ ਦਿੰਦਾ ਹੈ। ਰੈਪੋ: spf13/cobra (spf13/cobra · Apache-2.0) ਸਾਡੇ ਦੁਆਰਾ ਕਵਰ ਕੀਤੇ ਗਏ ਹਰੇਕ ਰੈਪੋ: berkayturanci/awesome-weekend-repos ਸਰੋਤ: - GitHub — spf13/cobra (github.com/spf13/cobra) - ਕੋਬਰਾ ਅਧਿਕਾਰਤ ਦਸਤਾਵੇਜ਼ (cobra.dev) ਪੂਰਾ ਲਿੰਕ ਉੱਪਰ ਦਿੱਤੇ ਵਰਣਨ ਵਿੱਚ ਹੈ। #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [pl] Cobra: framework CLI stojący za Kubernetes i Docker Framework Go obsługujący kubectl, Dockera i GitHub CLI. Twórz korporacyjne aplikacje Go CLI z flagami i podpoleceniami POSIX. • Cobra strukturuje złożone narzędzia za pomocą zagnieżdżonych podpoleceń i flag. • Flagi w pełni zgodne z POSIX obsługują opcje krótkie, długie i kaskadowe. • Automatyczne uzupełnianie powłoki obsługuje Bash, Zsh, Fish i PowerShell. • Inteligentne podpowiedzi literówek zapobiegają frustrującym błędom w wierszu poleceń. • Cobra obsługuje Kubernetes, Hugo, GitHub CLI i ekosystem Go. Repozytorium: spf13/cobra (spf13/cobra · Apache-2.0) Wszystkie omówione przez nas repozytorium: berkayturanci/awesome-weekend-repos Źródła: - GitHub — spf13/cobra (github.com/spf13/cobra) - Oficjalna dokumentacja Cobry (cobra.dev) Pełny link znajduje się w opisie powyżej. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [pt-BR] Cobra: O framework de CLI por trás do Kubernetes e Docker O framework Go que alimenta o kubectl, o Docker e a CLI do GitHub. Crie aplicativos CLI Go corporativos com flags e subcomandos POSIX. • O Cobra estrutura ferramentas complexas com subcomandos e flags aninhados. • Flags totalmente compatíveis com POSIX lidam com opções curtas, longas e em cascata. • O recurso de autocompletar comandos do shell oferece suporte a Bash, Zsh, Fish e PowerShell. • Sugestões inteligentes de erros de digitação evitam erros frustrantes na linha de comando. • O Cobra alimenta o Kubernetes, o Hugo, a CLI do GitHub e o ecossistema Go. Repositório: spf13/cobra (spf13/cobra · Apache-2.0) Todos os repositórios que abordamos: berkayturanci/awesome-weekend-repos Fontes: - GitHub — spf13/cobra (github.com/spf13/cobra) - Documentação oficial do Cobra (cobra.dev) O link completo está na descrição acima. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [ru] Cobra: CLI-фреймворк, стоящий за Kubernetes и Docker Фреймворк Go, используемый в kubectl, Docker и GitHub CLI. Создавайте корпоративные приложения Go CLI с флагами и подкомандами POSIX. • Cobra структурирует сложные инструменты с помощью вложенных подкоманд и флагов. • Полностью совместимые с POSIX флаги обрабатывают короткие, длинные и каскадные параметры. • Автоматическое завершение командной строки поддерживает Bash, Zsh, Fish и PowerShell. • Интеллектуальные подсказки по опечаткам предотвращают досадные ошибки в командной строке. • Cobra используется в Kubernetes, Hugo, GitHub CLI и экосистеме Go. Репозиторий: spf13/cobra (spf13/cobra · Apache-2.0) Все рассмотренные нами репозитории: berkayturanci/awesome-weekend-repos Источники: - GitHub — spf13/cobra (github.com/spf13/cobra) - Официальная документация Cobra (cobra.dev) Полная ссылка находится в описании выше. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [ta] Cobra: Kubernetes மற்றும் Docker-இன் பின்னணியில் உள்ள CLI கட்டமைப்பு kubectl, Docker, மற்றும் GitHub CLI-க்கு ஆற்றலளிக்கும் Go கட்டமைப்பு. POSIX கொடிகள் மற்றும் துணைக்கட்டளைகளைக் கொண்டு நிறுவன அளவிலான Go CLI செயலிகளை உருவாக்குங்கள். • கோப்ரா, சிக்கலான கருவிகளை உள்ளமைந்த துணைக்கட்டளைகள் மற்றும் கொடிகளைக் கொண்டு கட்டமைக்கிறது. • முழுமையாக POSIX-இணக்கமான கொடிகள், குறுகிய, நீண்ட, மற்றும் அடுக்கு விருப்பங்களைக் கையாளுகின்றன. • தானியங்கு ஷெல் நிறைவுகள் Bash, Zsh, Fish, மற்றும் PowerShell-ஐ ஆதரிக்கின்றன. • அறிவார்ந்த எழுத்துப்பிழை பரிந்துரைகள், எரிச்சலூட்டும் கட்டளை வரித் தவறுகளைத் தடுக்கின்றன. • கோப்ரா, Kubernetes, Hugo, GitHub CLI, மற்றும் Go சூழலமைப்பிற்கு ஆற்றலளிக்கிறது. ரெப்போ: spf13/cobra (spf13/cobra · Apache-2.0) நாங்கள் உள்ளடக்கிய ஒவ்வொரு ரெப்போவும்: berkayturanci/awesome-weekend-repos மூலங்கள்: - கிட்ஹப் — spf13/cobra (github.com/spf13/cobra) - கோப்ரா அதிகாரப்பூர்வ ஆவணங்கள் (cobra.dev) முழுமையான இணைப்பு மேலே உள்ள விளக்கத்தில் உள்ளது. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [te] కోబ్రా: కుబెర్నెటిస్ & డాకర్ వెనుక ఉన్న CLI ఫ్రేమ్‌వర్క్ kubectl, Docker, మరియు GitHub CLI లకు శక్తినిచ్చే Go ఫ్రేమ్‌వర్క్. POSIX ఫ్లాగ్‌లు మరియు సబ్‌కమాండ్‌లతో ఎంటర్‌ప్రైజ్ Go CLI యాప్‌లను రూపొందించండి. • కోబ్రా, అంతర్గత సబ్‌కమాండ్‌లు మరియు ఫ్లాగ్‌లతో సంక్లిష్టమైన సాధనాలను క్రమబద్ధీకరిస్తుంది. • పూర్తిగా POSIX-అనుకూలమైన ఫ్లాగ్‌లు చిన్న, పొడవైన, మరియు క్యాస్కేడింగ్ ఆప్షన్‌లను నిర్వహిస్తాయి. • ఆటోమేటిక్ షెల్ కంప్లీషన్‌లు Bash, Zsh, Fish, మరియు PowerShell లకు మద్దతు ఇస్తాయి. • తెలివైన టైపో సూచనలు విసుగు పుట్టించే కమాండ్-లైన్ పొరపాట్లను నివారిస్తాయి. • కోబ్రా, Kubernetes, Hugo, GitHub CLI, మరియు Go ఎకోసిస్టమ్‌కు శక్తినిస్తుంది. రిపో: spf13/cobra (spf13/cobra · Apache-2.0) మేము కవర్ చేసిన ప్రతి రిపో: berkayturanci/awesome-weekend-repos మూలాలు: - గిట్‌హబ్ — spf13/cobra (github.com/spf13/cobra) - కోబ్రా అధికారిక డాక్యుమెంటేషన్ (cobra.dev) పూర్తి లింక్ పైన వివరణలో ఉంది. #golang #developer #opensource #coding #terminal #softwareengineering #systemdesign #backend #devtok [uk] Cobra: CLI-фреймворк, на якому тримаються Kubernetes та Docker Фреймворк Go, що працює на kubectl, Docker та GitHub CLI. Створюйте корпоративні програми Go CLI за допомогою прапорців та підкоманд POSIX. • Cobra структурує складні інструменти з вкладеними підкомандами та прапорцями. • Повністю POSIX-сумісні прапорці обробляють короткі, довгі та каскадні параметри. • Автоматичне автодоповнення оболонки підтримує Bash, Zsh, Fish та PowerShell. • Інтелектуальні підказки щодо друкарських помилок запобігають неприємним помилкам у командному рядку. • Cobra працює на Kubernetes, Hugo, GitHub CLI та екосистемі Go. Репозиторій: spf13/cobra (spf13/cobra · Apache-2.0) Кожен репозиторій, який ми розглянули: berkayturanci/awesome-weekend-repos Джерела: - GitHub — spf13/cobra (github.com/spf13/cobra) - Офіційна документація Cobra (cobra.dev) Повне посилання знаходиться в описі вище. #golang #розробник #відкритийвихіднийкод #кодування #термінал #програмнаінженерія #системнийпроект #бекенд #devtok

    2 likes · 51 views
  6. 😤 写命令行工具,子命令和参数解析得自己写。Cobra 4.4 万星,Go 的命令行框架,kubectl、Hugo 都在用,子命令、帮助、补全自动生成。 spf13/cobra

    4 views

Achievements

Awards earned by the repositories spf13 owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.