[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CF6FQWHE7T0FK3RXRE4PNF":3,"skill-same:01M6CF6FQWHE7T0FK3RXRE4PNF":75},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":6,"ownerHtmlUrl":58,"ownerBlogUrl":6,"ownerDescription":59,"updatedAt":60,"install":61,"resources":74},"01M6CF6FQWHE7T0FK3RXRE4PNF","go",null,"Write native Go for cnos. Use when building the runtime\u002Fkernel, package tooling, command dispatch, HTTP services, or other low-level infrastructure in Go.","usurobor\u002Fcnos","usurobor","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F182342826?v=4","01M6CEXJCRMYD8HB2315FGB1Q8","Peter Lisovin","01M6CEXJH2RW04GQ2SNXY40F5S",9,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.eng\u002Fskills\u002Feng\u002Fgo\u002FSKILL.md",[],[5,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"integrations","build","simple","tooling","dispatch","use","process","orchestrator","write","command","how","shell","services","file","package","git","code","http","kernel","2026-11-10 10:12:30",false,"---\nname: go\ndescription: Write native Go for cnos. Use when building the runtime\u002Fkernel, package tooling, command dispatch, HTTP services, or other low-level infrastructure in Go.\nartifact_class: skill\nkata_surface: embedded\ngoverning_question: How do we write Go that keeps cnos simple, explicit, testable, and easy for any agent to build anywhere?\ntriggers:\n  - implementing cnos runtime\u002Fkernel code in Go\n  - creating package\u002Fcommand\u002Forchestrator infrastructure in Go\n  - building HTTP\u002Ffile\u002Fgit\u002Fprocess integrations in Go\n  - reviewing Go code for cnos\n  - migrating logic from OCaml or shell into Go\nscope: task-local\n---\n\n# Go\n\n## Core Principle\n\n**Write Go that is boring to run, easy to read, and explicit about failure.**\n\nUse packages to keep boundaries clear, concrete types to keep intent obvious, and error values to make degraded behavior visible. Prefer simple code paths that any agent can build and reason about on any machine.\n\n## Algorithm\n\n1. **Define** — name the model, the package boundaries, the failure policy, and the build\u002Ftest contract.\n2. **Unfold** — design the package layout, types, interfaces, context flow, error flow, resource lifecycle, and tests.\n3. **Rules** — keep the code explicit, small-package, low-magic, and hostile to silent fallback.\n4. **Verify** — build, test, and review the same failure classes across sibling surfaces.\n\n---\n\n## 1. Define\n\n### 1.0. Classify the artifact first\n\nUse this skill for Go code that belongs in the cnos runtime\u002Fkernel layer:\n\n- package management\n- command dispatch\n- orchestrator runtime\n- runtime contract emission\n- HTTP services\n- file\u002Fgit\u002Fprocess adapters\n- transport and protocol support\n\nDo **not** use this skill for:\n\n- product prose\n- package-authored Markdown skills\n- shell one-offs that should stay shell one-offs\n- workflow judgment rules better expressed as package skills\n\n### 1.1. Identify the parts\n\nA coherent Go subsystem has:\n\n- **Packages** — the primary unit of design\n- **Types** — concrete domain models\n- **Interfaces** — small consumer-owned seams\n- **Errors** — explicit outcome channel\n- **Context** — cancellation \u002F deadline propagation\n- **Observability** — structured `log\u002Fslog` state emission\n- **Adapters** — file, git, HTTP, process, archive, env\n- **Tests** — table-driven and subtest-based\n- **Build** — `go build` \u002F `go test` \u002F `go mod tidy`, no exotic toolchain\n  - ❌ Start with helpers and globals, then invent packages later\n  - ✅ Name the packages and types first, then fill in behavior\n\n### 1.2. Articulate how they fit\n\nPackages own responsibilities. Concrete types carry domain meaning. Interfaces appear where callers need substitution. Context flows from entrypoint downward. Errors make failure explicit. Adapters isolate side effects. Tests prove both success and degraded behavior.\n\n- ❌ One package owns CLI, HTTP, registry parsing, and git side effects together\n- ✅ `cmd\u002Fcn` wires `internal\u002Fruntime`, which uses `internal\u002Fdeps`, `internal\u002Fcontract`, and `internal\u002Ftransport`\n\n### 1.3. Name the failure mode\n\nGo code fails through:\n\n- **package sprawl** — blurry boundaries, cyclic dependencies, `util` buckets\n- **interface pollution** — interfaces declared before there is a real consumer need\n- **context leaks** — `context` stored in structs or dropped on the floor\n- **resource leaks** — failing to `defer` cleanup for files, network responses, or locks\n- **opaque exhaust** — unstructured `fmt.Printf` or `log.Printf` that hides system reality\n- **panic-driven control flow** — expected failure treated as exceptional collapse\n- **silent fallback** — error ignored, empty value fabricated, caller never told\n- **global state drift** — mutable package globals controlling behavior invisibly\n- **library fatalism** — `log.Fatal` \u002F `os.Exit` deep in reusable code\n  - ❌ `if err != nil { return nil }`\n  - ✅ `if err != nil { return fmt.Errorf(\"read package index: %w\", err) }`\n\n---\n\n## 2. Unfold\n\n### 2.1. Package design\n\n**Design packages around responsibilities, not layers of convenience.**\n\nUse short, lower-case package names. Avoid names that steal good local variable names or say nothing.\n\n- ❌ `common`, `utils`, `helpers`, `misc`\n- ✅ `deps`, `contract`, `transport`, `command`, `workflow`, `activation`\n\nFor cnos, prefer a shape like:\n\n```text\ncmd\u002Fcn\u002F                # CLI entrypoint only\ninternal\u002Fdeps\u002F         # package index, lockfile, restore\u002Finstall logic\ninternal\u002Fcontract\u002F     # runtime contract types + rendering\ninternal\u002Fcommand\u002F      # command registry + dispatch\ninternal\u002Fworkflow\u002F     # orchestrator IR + runner\ninternal\u002Factivation\u002F   # skill activation index + evaluator\ninternal\u002Ftransport\u002F    # peer\u002Fmail\u002FA2A support\ninternal\u002Fhost\u002F         # fs\u002Fgit\u002Fhttp\u002Fprocess\u002Farchive\u002Fenv adapters\n```\n\n- ❌ Import side-effecting adapters directly from every package\n- ✅ Keep impure adapters at the edge and pass them inward through concrete types or narrow interfaces\n\n### 2.2. Type design\n\nPrefer concrete types. Make the zero value useful when practical. Use structs and typed constants to model the domain directly.\n\n```go\n\u002F\u002F ✅ concrete domain model\ntype SourceKind string\n\nconst (\n    SourceReleaseHTTP SourceKind = \"release-http\"\n    SourceLocal       SourceKind = \"local\"\n)\n\ntype PackageLock struct {\n    Name    string\n    Version string\n    SHA256  string\n}\n```\n\nMake the zero value useful when it does not violate invariants.\n\n- ❌ Constructor required for a plain data holder with no invariants\n- ✅ Plain struct with zero-value-safe fields\n\nUse constructors only when you must enforce:\n\n- invariants\n- normalization\n- hidden\u002Finternal fields\n\n### 2.3. Interfaces\n\nDefine interfaces where they are consumed, not where they are produced. Use interfaces to express what a caller needs from a dependency.\n\n- ❌ Producer package exports `type Store interface { ... }` before any consumer needs it\n- ✅ Consumer package defines the minimal interface it needs\n\nPrefer:\n\n- concrete return types\n- narrow interfaces as inputs\n\n```go\n\u002F\u002F ✅ consumer-owned interface\ntype ReleaseFetcher interface {\n    FetchLatest(ctx context.Context) (Release, error)\n}\n```\n\nAvoid `any` \u002F `map[string]any` as a domain model except at true JSON boundaries.\n\n### 2.4. Context\n\n`context.Context` is a parameter, not a field.\n\nRules:\n\n- first parameter\n- never nil\n- do not store in structs\n- pass it through long-running or blocking operations\n- check `ctx.Done()` in loops and retries\n\n```go\nfunc (r *Registry) Resolve(ctx context.Context, name, version string) (Artifact, error) {\n    \u002F\u002F ...\n}\n```\n\n- ❌ `type Client struct { ctx context.Context }`\n- ❌ `func Resolve(name string) (...)`\n- ✅ `func Resolve(ctx context.Context, name string) (...)`\n\n### 2.5. Errors and fallback\n\nErrors are values. Fallback is policy.\n\nReturn errors for expected failures. Reserve panic for impossible states or invariants broken by programmer error.\n\nRules:\n\n- wrap with `%w`\n- error strings start lower-case\n- no trailing punctuation\n- never `log.Fatal` or `os.Exit` inside reusable packages\n- never silently fabricate success from failure\n- explicitly use `errors.Is` and `errors.As` to inspect wrapped errors for fallback logic\n\n```go\nif err != nil {\n    return fmt.Errorf(\"read package index: %w\", err)\n}\n\n\u002F\u002F ✅ Explicit inspection for fallback\nif errors.Is(err, fs.ErrNotExist) {\n    \u002F\u002F apply intentional policy ...\n}\n```\n\nFallbacks must be explicit and visible:\n\n- ❌ \"if missing, just return empty registry\"\n- ✅ \"if missing and local override is allowed, log\u002Fannotate the degraded path and continue by policy\"\n\nIf a fallback exists, document:\n\n- why it exists\n- when it applies\n- what it returns\n- what signal tells the caller it happened\n\n### 2.6. Side-effect boundaries\n\nKeep side effects at the edge. The core logic should decide:\n\n- what to load\n- what to validate\n- what to write\n- what to execute\n\nAdapters should only do:\n\n- filesystem\n- git\n- HTTP\n- archive\n- env\n- subprocess\n\nRules for adapters:\n\n- Inject adapters into domain structs at initialization.\n- Strictly ban package-level mutable state or `init()` wiring.\n  - ❌ Parse a package manifest inside the HTTP client\n  - ✅ HTTP client returns bytes; parser validates in the domain package\n\n### 2.7. Resource lifecycles\n\nResources must explicitly articulate their cleanup immediately after acquisition.\n\nRules:\n\n- use `defer` for `Close()`, `Unlock()`, or cleanup functions immediately after checking the acquisition error\n- never assume the garbage collector handles OS-level resources\n\n```go\nresp, err := client.Do(req)\nif err != nil {\n    return err\n}\n\u002F\u002F ✅ Teardown bonded to acquisition\ndefer resp.Body.Close()\n```\n\n- ❌ Acquire a file handle, then close it 50 lines later in a conditional branch\n- ✅ `defer f.Close()` on the line after the nil-error check\n\n### 2.8. Observability\n\nState must be structured and queryable, not opaque text.\n\nRules:\n\n- use `log\u002Fslog` for all runtime logging\n- attach key-value attributes (e.g., `slog.String(\"pkg\", name)`) rather than concatenating strings\n- log degraded paths explicitly when a fallback policy is triggered\n\n```go\n\u002F\u002F ✅ Structured state articulation\nslog.WarnContext(ctx, \"local override allowed, bypassing missing index\",\n    slog.String(\"package\", pkgName),\n    slog.String(\"fallback_path\", localPath),\n)\n```\n\n- ❌ `fmt.Printf(\"warning: package %s missing, using fallback\\n\", name)`\n- ✅ `slog.WarnContext(ctx, \"package index missing, applying local override policy\", slog.String(\"package\", name))`\n\n### 2.9. Concurrency\n\nDo not add goroutines because Go makes them cheap. Add them when they simplify the model or materially improve throughput.\n\nRules:\n\n- own cancellation with context\n- keep fan-out\u002Ffan-in explicit\n- prefer sequential correctness first\n- use channels when communication is the model, not as decoration\n  - ❌ Spawn goroutines for every restore step with no backpressure or cancellation\n  - ✅ Keep restore sequential until parallelism is justified by real latency\u002Fthroughput data\n\n### 2.10. Testing\n\nUse `go test` as the contract.\n\nFor deterministic logic:\n\n- table-driven tests\n- subtests with `t.Run`\n- golden\u002Ftext fixtures under `testdata\u002F` where useful\n\nFor adapters:\n\n- fake servers \u002F temp dirs \u002F test repos\n- explicit degraded-path tests\n\nTypical commands:\n\n```sh\ngo test .\u002F...\ngo test -race .\u002F...\ngo build .\u002F...\n```\n\nTest both:\n\n- success\n- degraded\u002Fmalformed\u002Fmissing\u002Funsupported cases\n  - ❌ Only test the happy path\n  - ✅ Test both the nominal path and the policy path\n\n### 2.11. Build and shipping\n\nAny agent on any machine should be able to build the runtime with the standard Go toolchain.\n\nKeep the build boring:\n\n- standard module layout\n- strict module hygiene (`go mod tidy`)\n- no custom code generation unless justified\n- minimal external dependencies\n- cross-compile only when needed, not as a daily burden\n\nPrefer stdlib first:\n\n- `encoding\u002Fjson`\n- `net\u002Fhttp`\n- `log\u002Fslog`\n- `archive\u002Ftar`\n- `compress\u002Fgzip`\n- `crypto\u002Fsha256`\n- `os\u002Fexec`\n- `path\u002Ffilepath`\n\n**Do not reimplement stdlib functions.** Before writing any helper, check whether the standard library already provides it. This is a recurring review finding:\n\n- ❌ Hand-rolled `contains(s, sub string) bool` → ✅ `strings.Contains`\n- ❌ Hand-rolled `joinArgs(args []string) string` → ✅ `strings.Join`\n- ❌ Hand-rolled `envMap()` copying `os.Environ()` → ✅ `os.Getenv` at point of use\n\nIf you write a utility function, verify it doesn't exist in `strings`, `slices`, `maps`, `path\u002Ffilepath`, `sort`, `bytes`, `fmt`, or `os` first.\n\n### 2.12. Schema and compatibility\n\n**Treat manifests, contracts, and IRs as public contracts.**\n\nWhen handling:\n\n- package manifests\n- runtime contract data\n- command\u002Forchestrator registries\n- lockfiles\n- indexes\n- workflow IR\n\nprefer:\n\n- additive evolution\n- explicit version fields\n- strict validation of required fields\n- tolerant handling of unknown fields when forward compatibility matters\n  - ❌ Silently coerce malformed config into defaults\n  - ✅ Reject malformed input with an explicit error and enough context to repair it\n\nIf a compatibility path exists, test it explicitly.\n\n**Sibling harnesses are contract surfaces too.** When a Go type defines a JSON schema (e.g. `pkg.Manifest` for `.cn\u002Fdeps.json`), every non-Go producer of that JSON — shell test harnesses, CI workflow steps, template-emitted defaults — is a contract surface on the same schema. The schema audit must extend to those producers. Mechanical check: for each `Parse*([]byte)` added or changed, grep the repo for non-Go writers of the same JSON shape and verify they still produce the declared schema. *Derives from: 3.56.2 (#250) — `cnos.kata\u002Flib.sh` `write_deps_json` was emitting object-syntax `packages` while the Go parser expected an array; the bug masked the mismatch until the bug itself was fixed.*\n\n  - ❌ Audit only the Go parser when changing a schema-bearing type\n  - ✅ `grep -rn '\"packages\"' src\u002F` and inspect every writer (Go, shell, workflow YAML)\n\n### 2.13. Determinism and reproducibility\n\nDeterministic output matters. For artifacts that are:\n\n- hashed\n- compared in tests\n- used in reports\n- stored for later diffing\n- emitted as runtime contracts\n\nensure:\n\n- stable ordering\n- canonical serialization\n- no dependence on map iteration order\n- no hidden timestamps unless intentionally included\n- no dependence on Go toolchain version for output bytes — `compress\u002Fgzip` flate output is **not** stable across minor Go versions. Pin the toolchain in `go.mod` and all CI `setup-go` calls. If cross-version byte-identity is required, use `gzip.NoCompression` or generate deterministic artifacts on CI rather than at author-time.\n  - ❌ Range over a map and render the result directly\n  - ❌ Assume `gzip.NewWriter` produces identical bytes on Go 1.22 and Go 1.24\n  - ✅ Sort keys\u002Fitems before rendering\n  - ✅ Pin Go version in `go.mod` + CI workflows when artifacts are hashed\n\n### 2.14. Idempotence and retry safety\n\nFor state-changing operations, define:\n\n- what happens on interruption\n- whether the operation is idempotent\n- what partial state is left behind\n- how cleanup works\n  - ❌ Write directly to the final target and hope the process completes\n  - ✅ Write to temp, validate, then atomically move into place\n\n### 2.15. Traceability and receipts\n\nFor operations like:\n\n- package restore\n- update\n- command registry rebuild\n- orchestrator execution\n- sync \u002F transport handling\n\ndecide explicitly:\n\n- what is returned\n- what is logged\n- what is written to status\u002Fdoctor\u002Fruntime contract\n- what receipt or trace event exists\n  - ❌ Degraded path only visible in transient stderr\n  - ✅ Degraded path visible in logs and\u002For structured runtime state\n\n### 2.16. Preserve cnos runtime boundaries\n\nKeep these boundaries explicit in Go code:\n\n- **skills** choose\n- **commands** dispatch\n- **orchestrators** execute\n- **extensions** provide capability\n\nDo not let core\u002Fruntime packages smear these concepts together.\n\n- ❌ A command registry that also decides skill activation logic\n- ✅ Separate registries and clear ownership\n\nThe kernel stays minimal. Package-driven commands are preferred over built-ins. Core should not accrete convenience commands casually. Mechanical first, semantic second — the kernel resolves, validates, registers, dispatches, and enforces policy. It does not do hidden interpretation or \"smart\" inference when explicit metadata should exist.\n\n### 2.17. Purity boundary: Parse vs Read\n\n*Derives from: INVARIANTS.md T-004 (source\u002Fartifact\u002Finstalled explicit)*\n\nPure functions operate on bytes\u002Fdata. IO functions operate on paths\u002Fnetwork. Keep them separate.\n\n```go\n\u002F\u002F Pure — no os imports, no IO\nfunc ParseManifestData(data []byte) (*PackageManifest, error)\n\n\u002F\u002F IO wrapper — calls pure function\nfunc ReadManifest(path string) (*PackageManifest, error) {\n    data, err := os.ReadFile(path)\n    if err != nil { return nil, err }\n    return ParseManifestData(data)\n}\n```\n\nThis mirrors the OCaml `src\u002Flib\u002F` (pure) vs `src\u002Fcmd\u002F` (IO) discipline.\n\n- ❌ `func ParseManifest(path string)` — mixes file IO with parsing\n- ✅ `func ParseManifestData(data []byte)` pure + `func ReadManifest(path string)` IO wrapper\n- ❌ `internal\u002Fpkg\u002F` importing `os`\n- ✅ `internal\u002Fpkg\u002F` has zero `os` imports; all IO enters through explicit wrappers elsewhere\n\n**Rule:** `Parse*` takes `[]byte`, returns typed data. `Read*` takes a path, calls `Parse*`. No mixing.\n\n**Diff-local generalization: do not introduce a parallel parser when a new pure parser is added in the same PR.** When a diff introduces a new canonical pure parser for a fact (`pkg.ParseInstalledManifestData([]byte) → *PackageManifest`), every other consumer of the same fact in the same diff is structurally bound to the new canonical. Hand-rolling an inline anonymous-struct unmarshal of the same JSON shape elsewhere in the diff is a parallel-parser violation even if every individual call-site obeys the parse\u002Fread split — `eng\u002Fgo §2.17` is also a \"one parser per fact\" rule, not only a \"no IO in pure code\" rule. Verification at authoring time: for every new `Parse*` introduced, grep the diff for sibling `json.Unmarshal` \u002F anonymous-struct decodes against the same JSON shape; replace each with a call to the new canonical parser. *Derives from: #274 F1 (severity C judgment) — the same diff that introduced `pkg.ParseInstalledManifestData` and the IO wrapper `restore.ReadInstalledManifest` (correctly applied to `restore.restoreOne`) also landed an inline anonymous-struct unmarshal in `doctor.checkPackages`. β caught it via `cdd\u002Freview §2.2.8` (authority-surface conflict); α fixed cleanly in round 2 by importing `pkg` into `doctor.go` and replacing the inline block with `pkg.ParseInstalledManifestData(manifestData)` (~5 lines net).*\n\n### 2.18. Dispatch boundary: cli\u002F owns dispatch only\n\n*Derives from: INVARIANTS.md T-002 (kernel remains minimal and trusted)*\n\n`cli\u002F` contains: types (`CommandSpec`, `Invocation`, `Command`, `Registry`) and thin command wrappers. Domain logic lives in domain packages.\n\n```\ninternal\u002Fcli\u002F         # dispatch only — types, registry, thin cmd_*.go wrappers\ninternal\u002Fdoctor\u002F      # doctor check logic\ninternal\u002Fpkgbuild\u002F    # build pipeline logic\ninternal\u002Frestore\u002F     # deps restore logic\ninternal\u002Fhubinit\u002F     # hub creation logic\ninternal\u002Fhubstatus\u002F   # status display logic\n```\n\n- ❌ `cmd_doctor.go` with 238 lines of check logic inline in `cli\u002F`\n- ✅ `cmd_doctor.go` as a 20-line wrapper calling `doctor.Run()`\n- ❌ Any `cmd_*.go` in `cli\u002F` with more than ~30 lines of domain logic\n- ✅ Domain logic extracted to its own package, `cmd_*.go` delegates\n\n**Rule:** If a command's logic exceeds a thin wrapper, extract it to a domain package. `cli\u002F` owns dispatch. Domain packages own logic.\n\n---\n\n## 3. Rules\n\n### 3.1. Package rule\n\nUse small packages with short, specific names.\n\n- ❌ `common`, `helpers`, `shared`\n- ✅ `deps`, `contract`, `workflow`, `activation`\n\nNo cyclic imports. No package whose only meaning is \"miscellaneous.\"\n\n### 3.2. Interface rule\n\nDefine interfaces in the consumer package. Return concrete types by default.\n\n- ❌ \"everything behind an interface\"\n- ✅ interfaces only where substitution\u002Ftest seams are real\n\n### 3.3. Context rule\n\nPass `context.Context` explicitly as the first parameter. Do not store it in structs. Do not drop it on the floor.\n\n### 3.4. Error and observability rule\n\nExpected failure returns `error`. Do not panic for policy-level failure. Wrap errors with context (`%w`). Inspect errors carefully with `errors.Is`\u002F`errors.As` before falling back. Do not swallow them. Use `log\u002Fslog` to articulate fallback state structurally.\n\n### 3.5. Fallback rule\n\nEvery fallback is a policy decision. Allowed only when:\n\n- the degraded behavior is intentional\n- the caller can still reason about the result\n- the fallback is visible through logs, return values, or explicit state\n  - ❌ `return nil` on malformed config and continue\n  - ✅ `return fmt.Errorf(\"parse activation index: %w\", err)`\n\n### 3.6. Resource rule\n\n`defer` must immediately follow the successful acquisition of files, network bodies, and locks. Never defer before the error check.\n\n### 3.7. Boundary rule\n\nParsing, validation, and planning belong in domain packages. Filesystem, git, HTTP, process, and env access belong in adapters. Dependency injection is required for adapters.\n\n### 3.8. Build rule\n\nRun before push:\n\n```sh\ngo mod tidy\ngo test .\u002F...\ngo build .\u002F...\n```\n\nIf the change adds concurrency or shared mutable state, also run:\n\n```sh\ngo test -race .\u002F...\n```\n\n### 3.9. Smell list\n\nTreat these as review smells:\n\n- `panic` for expected errors\n- `log.Fatal` \u002F `os.Exit` in libraries\n- `context.Context` stored in a struct\n- producer-owned interfaces with one implementation\n- package-level globals or `init()` used for runtime state\n- `map[string]any` as core domain model\n- package `util` \u002F `common`\n- hidden package globals controlling behavior\n- silent empty fallback on parse or IO error\n- goroutines with no cancellation path\n- unwrapped external errors\n- string-matching error messages instead of `errors.Is`\n- missing `defer` for `Close()` or `Unlock()`\n- unstructured `fmt.Printf` or `log.Printf` for system state\n- unstable map iteration in rendered\u002Fhashed output\n- non-atomic writes to final targets (no temp → validate → rename)\n- archive extraction without path-traversal validation\n- shell command built by string concatenation\n- precedence logic undocumented or untested\n- command\u002Forchestrator\u002Fextension boundaries smeared in one package\n- degraded path invisible outside transient stderr\n\n### 3.10. Shell and archive safety\n\nWhen using subprocesses or archives:\n\n- do not shell-escape by string concatenation\n- prefer argv-based execution (`exec.Command` with separate args)\n- validate destination paths before extraction\n- reject archive entries that escape the target directory\n- never log secrets\n  - ❌ `sh -c \"curl ... $USER_INPUT ...\"`\n  - ✅ `exec.CommandContext(ctx, \"curl\", \"-fsSL\", url)`\n\n### 3.11. Override precedence must be explicit\n\nIf behavior may come from:\n\n- flags\n- environment\n- config\n- runtime discovery\n- defaults\n\ndefine the precedence clearly and test it.\n\n- ❌ Precedence inferred from code order\n- ✅ Documented and table-tested precedence\n\n---\n\n## 4. Verify\n\n### 4.1. File-level check\n\n- Is the package boundary clear?\n- Is the type model concrete?\n- Is the failure policy explicit?\n\n### 4.2. Boundary check\n\n- Is IO at the edge?\n- Are adapters injected rather than globally accessed?\n- Are adapters separated from parsing\u002Fvalidation\u002Fplanning?\n\n### 4.3. Error, resource, and observability check\n\n- Are all expected failures returned as `error`?\n- Are fallbacks explicit, inspected via `errors.Is`, and justified?\n- Are resources reliably released via `defer`?\n- Is state emitted via `log\u002Fslog` (not `fmt.Printf`)?\n\n### 4.4. Context\u002Fconcurrency check\n\n- Does context flow correctly?\n- Are goroutines owned, bounded, and cancellable?\n\n### 4.5. Schema\u002Fcompatibility check\n\n- Are manifests and contracts validated strictly on required fields?\n- Are unknown fields tolerated where forward compatibility matters?\n- Is schema version checked explicitly?\n\n### 4.6. Determinism check\n\n- Is output ordering stable (sorted, not map-iteration-dependent)?\n- Are hashes computed over canonical content?\n\n### 4.7. Safety check\n\n- Are subprocesses argv-based (no string concatenation)?\n- Are archive extractions path-validated?\n- Are secrets excluded from logs?\n- Is override precedence documented and tested?\n\n### 4.8. cnos boundary check\n\n- Are command\u002Forchestrator\u002Fextension\u002Fskill boundaries preserved?\n- Is the kernel minimal (no casual built-in accretion)?\n- Are degraded paths visible in structured state, not just stderr?\n\n### 4.9. Build\u002Ftest check\n\n- `go mod tidy`\n- `go test .\u002F...`\n- `go build .\u002F...`\n- `go test -race .\u002F...` where warranted\n\n---\n\n## 5. Kata\n\n### 5.1. Kata A — package restore over HTTP\n\n**Scenario:** Implement first-party package restore from an artifact index and tarball.\n\n**Task:** Write Go code that:\n\n- resolves name + version\n- downloads artifact + checksum\n- verifies SHA-256\n- extracts into vendor\n- returns explicit errors for all malformed\u002Fmissing cases\n\n**Governing skills:** go, design, test\n\n**Inputs:**\n\n- package index fixture\n- checksum fixture\n- tarball fixture\n- malformed checksum\u002Findex cases\n\n**Expected artifacts:**\n\n- concrete package types\n- no producer-owned interfaces\n- explicit adapter boundaries (struct injection)\n- tests for happy path and malformed checksum\u002Findex cases\n\n**Verification:**\n\n- `go test .\u002F...`\n- no silent fallback from malformed index or checksum mismatch\n- no panic on network\u002FIO\u002Fparse failure\n\n**Common failures:**\n\n- hidden global HTTP client\n- parse logic inside transport layer\n- panic on malformed metadata\n- missing degraded-path tests\n\n**Reflection:**\n\n- Did the restore path stay mechanical and deterministic?\n- Did every fallback remain explicit and visible?\n\n### 5.2. Kata B — runtime contract builder\n\n**Scenario:** Extract runtime contract model\u002Frendering out of a large command handler.\n\n**Task:** Move:\n\n- types\n- validation\n- rendering helpers\n\ninto a reusable Go package, leaving command wiring in `cmd\u002Fcn`.\n\n**Governing skills:** go, design, write\n\n**Inputs:**\n\n- one existing command handler with mixed model\u002Frender\u002Fwiring logic\n- one expected JSON output\n- one expected text output\n\n**Expected artifacts:**\n\n- clear package boundary\n- concrete types\n- explicit command wiring\n- tests for JSON and text rendering\n\n**Verification:**\n\n- no system-truth logic left stranded in the CLI entry package\n- no cyclic imports\n- output stays stable under tests\n\n**Common failures:**\n\n- moving IO into the model package\n- inventing interfaces where concrete types suffice\n- leaving rendering behavior untested\n\n**Reflection:**\n\n- Did the extraction reduce command-layer ownership of system truth?\n- Did the new package keep IO at the edge?\n","# Go\n\n## Core Principle\n\n**Write Go that is boring to run, easy to read, and explicit about failure.**\n\nUse packages to keep boundaries clear, concrete types to keep intent obvious, and error values to make degraded behavior visible. Prefer simple code paths that any agent can build and reason about on any machine.\n\n## Algorithm\n\n1. **Define** — name the model, the package boundaries, the failure policy, and the build\u002Ftest contract.\n2. **Unfold** — design the package layout, types, interfaces, context flow, error flow, resource lifecycle, and tests.\n3. **Rules** — keep the code explicit, small-package, low-magic, and hostile to silent fallback.\n4. **Verify** — build, test, and review the same failure classes across sibling surfaces.\n\n---\n\n## 1. Define\n\n### 1.0. Classify the artifact first\n\nUse this skill for Go code that belongs in the cnos runtime\u002Fkernel layer:\n\n- package management\n- command dispatch\n- orchestrator runtime\n- runtime contract emission\n- HTTP services\n- file\u002Fgit\u002Fprocess adapters\n- transport and protocol support\n\nDo **not** use this skill for:\n\n- product prose\n- package-authored Markdown skills\n- shell one-offs that should stay shell one-offs\n- workflow judgment rules better expressed as package skills\n\n### 1.1. Identify the parts\n\nA coherent Go subsystem has:\n\n- **Packages** — the primary unit of design\n- **Types** — concrete domain models\n- **Interfaces** — small consumer-owned seams\n- **Errors** — explicit outcome channel\n- **Context** — cancellation \u002F deadline propagation\n- **Observability** — structured `log\u002Fslog` state emission\n- **Adapters** — file, git, HTTP, process, archive, env\n- **Tests** — table-driven and subtest-based\n- **Build** — `go build` \u002F `go test` \u002F `go mod tidy`, no exotic toolchain\n  - ❌ Start with helpers and globals, then invent packages later\n  - ✅ Name the packages and types first, then fill in behavior\n\n### 1.2. Articulate how they fit\n\nPackages own responsibilities. Concrete types carry domain meaning. Interfaces appear where callers need substitution. Context flows from entrypoint downward. Errors make failure explicit. Adapters isolate side effects. Tests prove both success and degraded behavior.\n\n- ❌ One package owns CLI, HTTP, registry parsing, and git side effects together\n- ✅ `cmd\u002Fcn` wires `internal\u002Fruntime`, which uses `internal\u002Fdeps`, `internal\u002Fcontract`, and `internal\u002Ftransport`\n\n### 1.3. Name the failure mode\n\nGo code fails through:\n\n- **package sprawl** — blurry boundaries, cyclic dependencies, `util` buckets\n- **interface pollution** — interfaces declared before there is a real consumer need\n- **context leaks** — `context` stored in structs or dropped on the floor\n- **resource leaks** — failing to `defer` cleanup for files, network responses, or locks\n- **opaque exhaust** — unstructured `fmt.Printf` or `log.Printf` that hides system reality\n- **panic-driven control flow** — expected failure treated as exceptional collapse\n- **silent fallback** — error ignored, empty value fabricated, caller never told\n- **global state drift** — mutable package globals controlling behavior invisibly\n- **library fatalism** — `log.Fatal` \u002F `os.Exit` deep in reusable code\n  - ❌ `if err != nil { return nil }`\n  - ✅ `if err != nil { return fmt.Errorf(\"read package index: %w\", err) }`\n\n---\n\n## 2. Unfold\n\n### 2.1. Package design\n\n**Design packages around responsibilities, not layers of convenience.**\n\nUse short, lower-case package names. Avoid names that steal good local variable names or say nothing.\n\n- ❌ `common`, `utils`, `helpers`, `misc`\n- ✅ `deps`, `contract`, `transport`, `command`, `workflow`, `activation`\n\nFor cnos, prefer a shape like:\n\n```text\ncmd\u002Fcn\u002F                # CLI entrypoint only\ninternal\u002Fdeps\u002F         # package index, lockfile, restore\u002Finstall logic\ninternal\u002Fcontract\u002F     # runtime contract types + rendering\ninternal\u002Fcommand\u002F      # command registry + dispatch\ninternal\u002Fworkflow\u002F     # orchestrator IR + runner\ninternal\u002Factivation\u002F   # skill activation index + evaluator\ninternal\u002Ftransport\u002F    # peer\u002Fmail\u002FA2A support\ninternal\u002Fhost\u002F         # fs\u002Fgit\u002Fhttp\u002Fprocess\u002Farchive\u002Fenv adapters\n```\n\n- ❌ Import side-effecting adapters directly from every package\n- ✅ Keep impure adapters at the edge and pass them inward through concrete types or narrow interfaces\n\n### 2.2. Type design\n\nPrefer concrete types. Make the zero value useful when practical. Use structs and typed constants to model the domain directly.\n\n```go\n\u002F\u002F ✅ concrete domain model\ntype SourceKind string\n\nconst (\n    SourceReleaseHTTP SourceKind = \"release-http\"\n    SourceLocal       SourceKind = \"local\"\n)\n\ntype PackageLock struct {\n    Name    string\n    Version string\n    SHA256  string\n}\n```\n\nMake the zero value useful when it does not violate invariants.\n\n- ❌ Constructor required for a plain data holder with no invariants\n- ✅ Plain struct with zero-value-safe fields\n\nUse constructors only when you must enforce:\n\n- invariants\n- normalization\n- hidden\u002Finternal fields\n\n### 2.3. Interfaces\n\nDefine interfaces where they are consumed, not where they are produced. Use interfaces to express what a caller needs from a dependency.\n\n- ❌ Producer package exports `type Store interface { ... }` before any consumer needs it\n- ✅ Consumer package defines the minimal interface it needs\n\nPrefer:\n\n- concrete return types\n- narrow interfaces as inputs\n\n```go\n\u002F\u002F ✅ consumer-owned interface\ntype ReleaseFetcher interface {\n    FetchLatest(ctx context.Context) (Release, error)\n}\n```\n\nAvoid `any` \u002F `map[string]any` as a domain model except at true JSON boundaries.\n\n### 2.4. Context\n\n`context.Context` is a parameter, not a field.\n\nRules:\n\n- first parameter\n- never nil\n- do not store in structs\n- pass it through long-running or blocking operations\n- check `ctx.Done()` in loops and retries\n\n```go\nfunc (r *Registry) Resolve(ctx context.Context, name, version string) (Artifact, error) {\n    \u002F\u002F ...\n}\n```\n\n- ❌ `type Client struct { ctx context.Context }`\n- ❌ `func Resolve(name string) (...)`\n- ✅ `func Resolve(ctx context.Context, name string) (...)`\n\n### 2.5. Errors and fallback\n\nErrors are values. Fallback is policy.\n\nReturn errors for expected failures. Reserve panic for impossible states or invariants broken by programmer error.\n\nRules:\n\n- wrap with `%w`\n- error strings start lower-case\n- no trailing punctuation\n- never `log.Fatal` or `os.Exit` inside reusable packages\n- never silently fabricate success from failure\n- explicitly use `errors.Is` and `errors.As` to inspect wrapped errors for fallback logic\n\n```go\nif err != nil {\n    return fmt.Errorf(\"read package index: %w\", err)\n}\n\n\u002F\u002F ✅ Explicit inspection for fallback\nif errors.Is(err, fs.ErrNotExist) {\n    \u002F\u002F apply intentional policy ...\n}\n```\n\nFallbacks must be explicit and visible:\n\n- ❌ \"if missing, just return empty registry\"\n- ✅ \"if missing and local override is allowed, log\u002Fannotate the degraded path and continue by policy\"\n\nIf a fallback exists, document:\n\n- why it exists\n- when it applies\n- what it returns\n- what signal tells the caller it happened\n\n### 2.6. Side-effect boundaries\n\nKeep side effects at the edge. The core logic should decide:\n\n- what to load\n- what to validate\n- what to write\n- what to execute\n\nAdapters should only do:\n\n- filesystem\n- git\n- HTTP\n- archive\n- env\n- subprocess\n\nRules for adapters:\n\n- Inject adapters into domain structs at initialization.\n- Strictly ban package-level mutable state or `init()` wiring.\n  - ❌ Parse a package manifest inside the HTTP client\n  - ✅ HTTP client returns bytes; parser validates in the domain package\n\n### 2.7. Resource lifecycles\n\nResources must explicitly articulate their cleanup immediately after acquisition.\n\nRules:\n\n- use `defer` for `Close()`, `Unlock()`, or cleanup functions immediately after checking the acquisition error\n- never assume the garbage collector handles OS-level resources\n\n```go\nresp, err := client.Do(req)\nif err != nil {\n    return err\n}\n\u002F\u002F ✅ Teardown bonded to acquisition\ndefer resp.Body.Close()\n```\n\n- ❌ Acquire a file handle, then close it 50 lines later in a conditional branch\n- ✅ `defer f.Close()` on the line after the nil-error check\n\n### 2.8. Observability\n\nState must be structured and queryable, not opaque text.\n\nRules:\n\n- use `log\u002Fslog` for all runtime logging\n- attach key-value attributes (e.g., `slog.String(\"pkg\", name)`) rather than concatenating strings\n- log degraded paths explicitly when a fallback policy is triggered\n\n```go\n\u002F\u002F ✅ Structured state articulation\nslog.WarnContext(ctx, \"local override allowed, bypassing missing index\",\n    slog.String(\"package\", pkgName),\n    slog.String(\"fallback_path\", localPath),\n)\n```\n\n- ❌ `fmt.Printf(\"warning: package %s missing, using fallback\\n\", name)`\n- ✅ `slog.WarnContext(ctx, \"package index missing, applying local override policy\", slog.String(\"package\", name))`\n\n### 2.9. Concurrency\n\nDo not add goroutines because Go makes them cheap. Add them when they simplify the model or materially improve throughput.\n\nRules:\n\n- own cancellation with context\n- keep fan-out\u002Ffan-in explicit\n- prefer sequential correctness first\n- use channels when communication is the model, not as decoration\n  - ❌ Spawn goroutines for every restore step with no backpressure or cancellation\n  - ✅ Keep restore sequential until parallelism is justified by real latency\u002Fthroughput data\n\n### 2.10. Testing\n\nUse `go test` as the contract.\n\nFor deterministic logic:\n\n- table-driven tests\n- subtests with `t.Run`\n- golden\u002Ftext fixtures under `testdata\u002F` where useful\n\nFor adapters:\n\n- fake servers \u002F temp dirs \u002F test repos\n- explicit degraded-path tests\n\nTypical commands:\n\n```sh\ngo test .\u002F...\ngo test -race .\u002F...\ngo build .\u002F...\n```\n\nTest both:\n\n- success\n- degraded\u002Fmalformed\u002Fmissing\u002Funsupported cases\n  - ❌ Only test the happy path\n  - ✅ Test both the nominal path and the policy path\n\n### 2.11. Build and shipping\n\nAny agent on any machine should be able to build the runtime with the standard Go toolchain.\n\nKeep the build boring:\n\n- standard module layout\n- strict module hygiene (`go mod tidy`)\n- no custom code generation unless justified\n- minimal external dependencies\n- cross-compile only when needed, not as a daily burden\n\nPrefer stdlib first:\n\n- `encoding\u002Fjson`\n- `net\u002Fhttp`\n- `log\u002Fslog`\n- `archive\u002Ftar`\n- `compress\u002Fgzip`\n- `crypto\u002Fsha256`\n- `os\u002Fexec`\n- `path\u002Ffilepath`\n\n**Do not reimplement stdlib functions.** Before writing any helper, check whether the standard library already provides it. This is a recurring review finding:\n\n- ❌ Hand-rolled `contains(s, sub string) bool` → ✅ `strings.Contains`\n- ❌ Hand-rolled `joinArgs(args []string) string` → ✅ `strings.Join`\n- ❌ Hand-rolled `envMap()` copying `os.Environ()` → ✅ `os.Getenv` at point of use\n\nIf you write a utility function, verify it doesn't exist in `strings`, `slices`, `maps`, `path\u002Ffilepath`, `sort`, `bytes`, `fmt`, or `os` first.\n\n### 2.12. Schema and compatibility\n\n**Treat manifests, contracts, and IRs as public contracts.**\n\nWhen handling:\n\n- package manifests\n- runtime contract data\n- command\u002Forchestrator registries\n- lockfiles\n- indexes\n- workflow IR\n\nprefer:\n\n- additive evolution\n- explicit version fields\n- strict validation of required fields\n- tolerant handling of unknown fields when forward compatibility matters\n  - ❌ Silently coerce malformed config into defaults\n  - ✅ Reject malformed input with an explicit error and enough context to repair it\n\nIf a compatibility path exists, test it explicitly.\n\n**Sibling harnesses are contract surfaces too.** When a Go type defines a JSON schema (e.g. `pkg.Manifest` for `.cn\u002Fdeps.json`), every non-Go producer of that JSON — shell test harnesses, CI workflow steps, template-emitted defaults — is a contract surface on the same schema. The schema audit must extend to those producers. Mechanical check: for each `Parse*([]byte)` added or changed, grep the repo for non-Go writers of the same JSON shape and verify they still produce the declared schema. *Derives from: 3.56.2 (#250) — `cnos.kata\u002Flib.sh` `write_deps_json` was emitting object-syntax `packages` while the Go parser expected an array; the bug masked the mismatch until the bug itself was fixed.*\n\n  - ❌ Audit only the Go parser when changing a schema-bearing type\n  - ✅ `grep -rn '\"packages\"' src\u002F` and inspect every writer (Go, shell, workflow YAML)\n\n### 2.13. Determinism and reproducibility\n\nDeterministic output matters. For artifacts that are:\n\n- hashed\n- compared in tests\n- used in reports\n- stored for later diffing\n- emitted as runtime contracts\n\nensure:\n\n- stable ordering\n- canonical serialization\n- no dependence on map iteration order\n- no hidden timestamps unless intentionally included\n- no dependence on Go toolchain version for output bytes — `compress\u002Fgzip` flate output is **not** stable across minor Go versions. Pin the toolchain in `go.mod` and all CI `setup-go` calls. If cross-version byte-identity is required, use `gzip.NoCompression` or generate deterministic artifacts on CI rather than at author-time.\n  - ❌ Range over a map and render the result directly\n  - ❌ Assume `gzip.NewWriter` produces identical bytes on Go 1.22 and Go 1.24\n  - ✅ Sort keys\u002Fitems before rendering\n  - ✅ Pin Go version in `go.mod` + CI workflows when artifacts are hashed\n\n### 2.14. Idempotence and retry safety\n\nFor state-changing operations, define:\n\n- what happens on interruption\n- whether the operation is idempotent\n- what partial state is left behind\n- how cleanup works\n  - ❌ Write directly to the final target and hope the process completes\n  - ✅ Write to temp, validate, then atomically move into place\n\n### 2.15. Traceability and receipts\n\nFor operations like:\n\n- package restore\n- update\n- command registry rebuild\n- orchestrator execution\n- sync \u002F transport handling\n\ndecide explicitly:\n\n- what is returned\n- what is logged\n- what is written to status\u002Fdoctor\u002Fruntime contract\n- what receipt or trace event exists\n  - ❌ Degraded path only visible in transient stderr\n  - ✅ Degraded path visible in logs and\u002For structured runtime state\n\n### 2.16. Preserve cnos runtime boundaries\n\nKeep these boundaries explicit in Go code:\n\n- **skills** choose\n- **commands** dispatch\n- **orchestrators** execute\n- **extensions** provide capability\n\nDo not let core\u002Fruntime packages smear these concepts together.\n\n- ❌ A command registry that also decides skill activation logic\n- ✅ Separate registries and clear ownership\n\nThe kernel stays minimal. Package-driven commands are preferred over built-ins. Core should not accrete convenience commands casually. Mechanical first, semantic second — the kernel resolves, validates, registers, dispatches, and enforces policy. It does not do hidden interpretation or \"smart\" inference when explicit metadata should exist.\n\n### 2.17. Purity boundary: Parse vs Read\n\n*Derives from: INVARIANTS.md T-004 (source\u002Fartifact\u002Finstalled explicit)*\n\nPure functions operate on bytes\u002Fdata. IO functions operate on paths\u002Fnetwork. Keep them separate.\n\n```go\n\u002F\u002F Pure — no os imports, no IO\nfunc ParseManifestData(data []byte) (*PackageManifest, error)\n\n\u002F\u002F IO wrapper — calls pure function\nfunc ReadManifest(path string) (*PackageManifest, error) {\n    data, err := os.ReadFile(path)\n    if err != nil { return nil, err }\n    return ParseManifestData(data)\n}\n```\n\nThis mirrors the OCaml `src\u002Flib\u002F` (pure) vs `src\u002Fcmd\u002F` (IO) discipline.\n\n- ❌ `func ParseManifest(path string)` — mixes file IO with parsing\n- ✅ `func ParseManifestData(data []byte)` pure + `func ReadManifest(path string)` IO wrapper\n- ❌ `internal\u002Fpkg\u002F` importing `os`\n- ✅ `internal\u002Fpkg\u002F` has zero `os` imports; all IO enters through explicit wrappers elsewhere\n\n**Rule:** `Parse*` takes `[]byte`, returns typed data. `Read*` takes a path, calls `Parse*`. No mixing.\n\n**Diff-local generalization: do not introduce a parallel parser when a new pure parser is added in the same PR.** When a diff introduces a new canonical pure parser for a fact (`pkg.ParseInstalledManifestData([]byte) → *PackageManifest`), every other consumer of the same fact in the same diff is structurally bound to the new canonical. Hand-rolling an inline anonymous-struct unmarshal of the same JSON shape elsewhere in the diff is a parallel-parser violation even if every individual call-site obeys the parse\u002Fread split — `eng\u002Fgo §2.17` is also a \"one parser per fact\" rule, not only a \"no IO in pure code\" rule. Verification at authoring time: for every new `Parse*` introduced, grep the diff for sibling `json.Unmarshal` \u002F anonymous-struct decodes against the same JSON shape; replace each with a call to the new canonical parser. *Derives from: #274 F1 (severity C judgment) — the same diff that introduced `pkg.ParseInstalledManifestData` and the IO wrapper `restore.ReadInstalledManifest` (correctly applied to `restore.restoreOne`) also landed an inline anonymous-struct unmarshal in `doctor.checkPackages`. β caught it via `cdd\u002Freview §2.2.8` (authority-surface conflict); α fixed cleanly in round 2 by importing `pkg` into `doctor.go` and replacing the inline block with `pkg.ParseInstalledManifestData(manifestData)` (~5 lines net).*\n\n### 2.18. Dispatch boundary: cli\u002F owns dispatch only\n\n*Derives from: INVARIANTS.md T-002 (kernel remains minimal and trusted)*\n\n`cli\u002F` contains: types (`CommandSpec`, `Invocation`, `Command`, `Registry`) and thin command wrappers. Domain logic lives in domain packages.\n\n```\ninternal\u002Fcli\u002F         # dispatch only — types, registry, thin cmd_*.go wrappers\ninternal\u002Fdoctor\u002F      # doctor check logic\ninternal\u002Fpkgbuild\u002F    # build pipeline logic\ninternal\u002Frestore\u002F     # deps restore logic\ninternal\u002Fhubinit\u002F     # hub creation logic\ninternal\u002Fhubstatus\u002F   # status display logic\n```\n\n- ❌ `cmd_doctor.go` with 238 lines of check logic inline in `cli\u002F`\n- ✅ `cmd_doctor.go` as a 20-line wrapper calling `doctor.Run()`\n- ❌ Any `cmd_*.go` in `cli\u002F` with more than ~30 lines of domain logic\n- ✅ Domain logic extracted to its own package, `cmd_*.go` delegates\n\n**Rule:** If a command's logic exceeds a thin wrapper, extract it to a domain package. `cli\u002F` owns dispatch. Domain packages own logic.\n\n---\n\n## 3. Rules\n\n### 3.1. Package rule\n\nUse small packages with short, specific names.\n\n- ❌ `common`, `helpers`, `shared`\n- ✅ `deps`, `contract`, `workflow`, `activation`\n\nNo cyclic imports. No package whose only meaning is \"miscellaneous.\"\n\n### 3.2. Interface rule\n\nDefine interfaces in the consumer package. Return concrete types by default.\n\n- ❌ \"everything behind an interface\"\n- ✅ interfaces only where substitution\u002Ftest seams are real\n\n### 3.3. Context rule\n\nPass `context.Context` explicitly as the first parameter. Do not store it in structs. Do not drop it on the floor.\n\n### 3.4. Error and observability rule\n\nExpected failure returns `error`. Do not panic for policy-level failure. Wrap errors with context (`%w`). Inspect errors carefully with `errors.Is`\u002F`errors.As` before falling back. Do not swallow them. Use `log\u002Fslog` to articulate fallback state structurally.\n\n### 3.5. Fallback rule\n\nEvery fallback is a policy decision. Allowed only when:\n\n- the degraded behavior is intentional\n- the caller can still reason about the result\n- the fallback is visible through logs, return values, or explicit state\n  - ❌ `return nil` on malformed config and continue\n  - ✅ `return fmt.Errorf(\"parse activation index: %w\", err)`\n\n### 3.6. Resource rule\n\n`defer` must immediately follow the successful acquisition of files, network bodies, and locks. Never defer before the error check.\n\n### 3.7. Boundary rule\n\nParsing, validation, and planning belong in domain packages. Filesystem, git, HTTP, process, and env access belong in adapters. Dependency injection is required for adapters.\n\n### 3.8. Build rule\n\nRun before push:\n\n```sh\ngo mod tidy\ngo test .\u002F...\ngo build .\u002F...\n```\n\nIf the change adds concurrency or shared mutable state, also run:\n\n```sh\ngo test -race .\u002F...\n```\n\n### 3.9. Smell list\n\nTreat these as review smells:\n\n- `panic` for expected errors\n- `log.Fatal` \u002F `os.Exit` in libraries\n- `context.Context` stored in a struct\n- producer-owned interfaces with one implementation\n- package-level globals or `init()` used for runtime state\n- `map[string]any` as core domain model\n- package `util` \u002F `common`\n- hidden package globals controlling behavior\n- silent empty fallback on parse or IO error\n- goroutines with no cancellation path\n- unwrapped external errors\n- string-matching error messages instead of `errors.Is`\n- missing `defer` for `Close()` or `Unlock()`\n- unstructured `fmt.Printf` or `log.Printf` for system state\n- unstable map iteration in rendered\u002Fhashed output\n- non-atomic writes to final targets (no temp → validate → rename)\n- archive extraction without path-traversal validation\n- shell command built by string concatenation\n- precedence logic undocumented or untested\n- command\u002Forchestrator\u002Fextension boundaries smeared in one package\n- degraded path invisible outside transient stderr\n\n### 3.10. Shell and archive safety\n\nWhen using subprocesses or archives:\n\n- do not shell-escape by string concatenation\n- prefer argv-based execution (`exec.Command` with separate args)\n- validate destination paths before extraction\n- reject archive entries that escape the target directory\n- never log secrets\n  - ❌ `sh -c \"curl ... $USER_INPUT ...\"`\n  - ✅ `exec.CommandContext(ctx, \"curl\", \"-fsSL\", url)`\n\n### 3.11. Override precedence must be explicit\n\nIf behavior may come from:\n\n- flags\n- environment\n- config\n- runtime discovery\n- defaults\n\ndefine the precedence clearly and test it.\n\n- ❌ Precedence inferred from code order\n- ✅ Documented and table-tested precedence\n\n---\n\n## 4. Verify\n\n### 4.1. File-level check\n\n- Is the package boundary clear?\n- Is the type model concrete?\n- Is the failure policy explicit?\n\n### 4.2. Boundary check\n\n- Is IO at the edge?\n- Are adapters injected rather than globally accessed?\n- Are adapters separated from parsing\u002Fvalidation\u002Fplanning?\n\n### 4.3. Error, resource, and observability check\n\n- Are all expected failures returned as `error`?\n- Are fallbacks explicit, inspected via `errors.Is`, and justified?\n- Are resources reliably released via `defer`?\n- Is state emitted via `log\u002Fslog` (not `fmt.Printf`)?\n\n### 4.4. Context\u002Fconcurrency check\n\n- Does context flow correctly?\n- Are goroutines owned, bounded, and cancellable?\n\n### 4.5. Schema\u002Fcompatibility check\n\n- Are manifests and contracts validated strictly on required fields?\n- Are unknown fields tolerated where forward compatibility matters?\n- Is schema version checked explicitly?\n\n### 4.6. Determinism check\n\n- Is output ordering stable (sorted, not map-iteration-dependent)?\n- Are hashes computed over canonical content?\n\n### 4.7. Safety check\n\n- Are subprocesses argv-based (no string concatenation)?\n- Are archive extractions path-validated?\n- Are secrets excluded from logs?\n- Is override precedence documented and tested?\n\n### 4.8. cnos boundary check\n\n- Are command\u002Forchestrator\u002Fextension\u002Fskill boundaries preserved?\n- Is the kernel minimal (no casual built-in accretion)?\n- Are degraded paths visible in structured state, not just stderr?\n\n### 4.9. Build\u002Ftest check\n\n- `go mod tidy`\n- `go test .\u002F...`\n- `go build .\u002F...`\n- `go test -race .\u002F...` where warranted\n\n---\n\n## 5. Kata\n\n### 5.1. Kata A — package restore over HTTP\n\n**Scenario:** Implement first-party package restore from an artifact index and tarball.\n\n**Task:** Write Go code that:\n\n- resolves name + version\n- downloads artifact + checksum\n- verifies SHA-256\n- extracts into vendor\n- returns explicit errors for all malformed\u002Fmissing cases\n\n**Governing skills:** go, design, test\n\n**Inputs:**\n\n- package index fixture\n- checksum fixture\n- tarball fixture\n- malformed checksum\u002Findex cases\n\n**Expected artifacts:**\n\n- concrete package types\n- no producer-owned interfaces\n- explicit adapter boundaries (struct injection)\n- tests for happy path and malformed checksum\u002Findex cases\n\n**Verification:**\n\n- `go test .\u002F...`\n- no silent fallback from malformed index or checksum mismatch\n- no panic on network\u002FIO\u002Fparse failure\n\n**Common failures:**\n\n- hidden global HTTP client\n- parse logic inside transport layer\n- panic on malformed metadata\n- missing degraded-path tests\n\n**Reflection:**\n\n- Did the restore path stay mechanical and deterministic?\n- Did every fallback remain explicit and visible?\n\n### 5.2. Kata B — runtime contract builder\n\n**Scenario:** Extract runtime contract model\u002Frendering out of a large command handler.\n\n**Task:** Move:\n\n- types\n- validation\n- rendering helpers\n\ninto a reusable Go package, leaving command wiring in `cmd\u002Fcn`.\n\n**Governing skills:** go, design, write\n\n**Inputs:**\n\n- one existing command handler with mixed model\u002Frender\u002Fwiring logic\n- one expected JSON output\n- one expected text output\n\n**Expected artifacts:**\n\n- clear package boundary\n- concrete types\n- explicit command wiring\n- tests for JSON and text rendering\n\n**Verification:**\n\n- no system-truth logic left stranded in the CLI entry package\n- no cyclic imports\n- output stays stable under tests\n\n**Common failures:**\n\n- moving IO into the model package\n- inventing interfaces where concrete types suffice\n- leaving rendering behavior untested\n\n**Reflection:**\n\n- Did the extraction reduce command-layer ownership of system truth?\n- Did the new package keep IO at the edge?\n",{"name":5,"scope":43,"triggers":44,"description":7,"kata_surface":50,"artifact_class":51,"governing_question":52},"task-local",[45,46,47,48,49],"implementing cnos runtime\u002Fkernel code in Go","creating package\u002Fcommand\u002Forchestrator infrastructure in Go","building HTTP\u002Ffile\u002Fgit\u002Fprocess integrations in Go","reviewing Go code for cnos","migrating logic from OCaml or shell into Go","embedded","skill","How do we write Go that keeps cnos simple, explicit, testable, and easy for any agent to build anywhere?","main","fb527e6c4bfb75c71fa75d6471b3aa3da32106d4","src\u002Fpackages\u002Fcnos.eng\u002Fskills\u002Feng\u002Fgo",0,"https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos","https:\u002F\u002Fgithub.com\u002Fusurobor","Coherence engineer. Building git-CN.","2026-11-07 14:25:44",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add usurobor\u002Fcnos --skill go",{"tool":67,"command":68},"bunx","bunx skills add usurobor\u002Fcnos --skill go",{"tool":70,"command":71},"pnpm","pnpm dlx skills add usurobor\u002Fcnos --skill go","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.eng\u002Fskills\u002Feng\u002Fgo\u002FSKILL.md",true,[],[76,92,108,136,151,171],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":38},"01M6CF8RWQPM0VXZG06XMR0FFX","issues\u002Ftriage","Issue triage doctrine pointer. Use when classifying a new issue, deciding dispatch eligibility, or deciding whether to close\u002Fsupersede\u002Fdefer.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.issues\u002Fskills\u002Ftriage\u002FSKILL.md",[],[83,84,85,86,87,29,88,89,24,23,90,91],"triage","issues","issues triage","issue triage","SET","decision","public","issue","doctrine",{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":98,"publishedAt":38},"01M6CF8PJ812DD4APZ3WE8X67B","issues\u002Ftaxonomy","Issue label taxonomy pointer. Use when classifying an issue's kind\u002Farea\u002Fpriority\u002Feffort\u002Fstatus\u002Fprotocol\u002Fdispatch labels, or when the board needs to interpret them.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.issues\u002Fskills\u002Ftaxonomy\u002FSKILL.md",[],[84,99,100,101,102,103,87,104,89,105,24,23,106,90,107],"taxonomy","issues taxonomy","github","status","protocol","open","board","github issue","issue labels",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":124,"publishedAt":38},"01M6CF8KBMZ4D0CDJQ3PF1YVTP","issues\u002Fmap","Issue-board (Issue Pivot) generation domain. Use when reasoning about `cn issues map`'s fetch, taxonomy-parse, effort-computation, and render pipeline, or about the board's JSON\u002FHTML output contract.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.issues\u002Fskills\u002Fmap\u002FSKILL.md",[114,119],{"categoryNo":115,"categoryName":116,"taxonomyType":117,"taxonomyTypeDesc":118},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":120,"categoryName":121,"taxonomyType":122,"taxonomyTypeDesc":123},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[84,125,101,126,127,128,87,129,99,104,29,130,131,105,132,133,134,135,24,90],"issues map","reasoning","data","pipeline","api","json","README","edit","interactive","fetch","generated",{"skillNo":137,"name":84,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":38},"01M6CF8CZQH7G7B7RZPANQWR4G","cnos.issues package entrypoint. Use when reasoning about issue taxonomy, the Issue Pivot \u002F issue-board (`cn issues map`), the read-only CDS issue-state evaluator (`cn issues fsm evaluate`), or the current command-dispatch disposition of issue tooling.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.issues\u002FSKILL.md",[],[84,101,142,143,144,145,146,33,147,99,104,29,88,148,131,28,24,149,23,150],"pr","current state","run","artifacts","state","boundary","branch","only","cds",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":157,"publishedAt":38},"01M6CF896XKSRQVB1CSHY8GSXB","receipt-stream","Cross-cycle receipt-stream doctrine for protocol-iteration. Use when γ closes a cycle and writes the per-cycle iteration artifact (`cdd-iteration.md`), when γ updates the cross-cycle aggregator at `.cdd\u002Fiterations\u002FINDEX.md`, when ε reads the receipt stream across cycles to surface protocol-gap patterns, when a finding's disposition lands a cross-repo patch and the cross-repo trace bundle attaches, or when a courtesy empty-findings stub is written for a `protocol_gap_count == 0` cycle.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.handoff\u002Fskills\u002Fhandoff\u002Freceipt-stream\u002FSKILL.md",[],[158,159,145,103,160,29,161,162,163,89,164,165,166,167,24,50,168,169,170,91],"receipt stream","handoff","index","learning","format","trace","repo","closeout","read","channel","patch","shape","cdd",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":38},"01M6CF84VCBME6RK8V6HAVDM8Z","mid-flight","Mid-flight γ→in-flight-α rescue channel. Use when γ needs to change a load-bearing fact (pinned axis, scope, AC, blocker) after α has begun coding, when γ edits the cycle's GitHub issue body mid-cycle, or when a spec change lands on origin\u002Fmain while α\u002Fβ polling sessions are in-flight.","https:\u002F\u002Fgithub.com\u002Fusurobor\u002Fcnos\u002Fblob\u002Fmain\u002Fsrc\u002Fpackages\u002Fcnos.handoff\u002Fskills\u002Fhandoff\u002Fmid-flight\u002FSKILL.md",[],[178,101,179,180,32,181,29,182,183,148,164,166,24,149,23,184,106,185,186,187],"mid flight","change","sessions","cache","pin","coordination","up","Legacy","gamma","artifact channel"]