Skip to content

docs: state the agent contract for this repo (#30) - #35

Merged
antoinetoussaint-byte merged 3 commits into
mainfrom
issue-30-adopt-the-fleet-agent-context-standard-agents-md
Sep 22, 2026
Merged

antoinetoussaint-byte merged 3 commits into
mainfrom
issue-30-adopt-the-fleet-agent-context-standard-agents-md

Conversation

@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

Closes #30.

Summary

  • Adds a root AGENTS.md (143 lines, under the ~150 guidance): what this runtime owns and does not own, the six behavioural rules from obin-ai/handbook#68, the build/test loop derived from .github/workflows/go.yml, and where depth lives.
  • Each rule is anchored in something true here rather than restated generically — the rules only change behaviour if they point at this repo's own code. Rule 4 points at loadConfig resolving every address, port and secret through the SDK and at the derived token-exchange URLs; rule 5 points at validate() already separating three causes a single generic message used to conflate; rule 6 points at the suite being hermetic, so a green run says nothing about a real composition.
  • No .claude/skills/ and no CLAUDE.md. Neither is invented: this repo is one package and one CI job, so there is no repeated procedure to push out of the root file, and the standard makes CLAUDE.md a pointer only where one already exists. AGENTS.md names .claude/skills/ as the place to add one instead of growing the file.

Classification: neither fix nor hack. This adds no behaviour; no source file is touched.

Test plan

Every command in the new file was run in this worktree, not read off the workflow:

  • go mod download && go mod verify — all modules verified
  • go test -race ./... -count=1 -timeout=5m — ok, 18.5s
  • go vet ./... — clean
  • test -z "$(gofmt -l ./*.go)" — empty
  • go mod tidy leaves go.mod/go.sum unchanged (the file claims this)
  • Every path cited in AGENTS.md resolves from the repository root; every exported name it lists exists in solution.go/gateway_error.go
  • The ~20s suite time and its two wall-clock tests are measured: TestHeartbeatStopsQuotingAnEndlesslyChangingReason 10.01s, TestBeatIsBoundedByTheCredentialsExpiry 5.04s
  • The ./*.go formatting glob covering only the root package is read from the workflow, not assumed

Not verified: nothing in AGENTS.md was exercised against a real composition — no codefly run solution, no live host, gateway or accounts. The claims about those surfaces are restatements of README.md and of the issues it cites (codefly-dev/core#382, #365, codefly-dev/cli#717), not observations I made. The release sentence is inferred from the repository's state — v0.0.9 points at main's HEAD and there is no release workflow — not from having cut one.

🤖 Generated with Claude Code

An agent starting here had no statement of what this runtime owns, what it
does not, or how to behave when something does not work. The failure that
produced the fleet standard was measured against these runtimes: an agent
hand-wrote the environment they exist to resolve, and a sibling runtime
skipped registration silently.

Commands are derived from the workflow and were run in this worktree.

Refs obin-ai/handbook#68

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review of the new file found it asserting a safety property this runtime
does not have: the consumed-API projection is read at serve time, never
reaches validate(), and a malformed one degrades to a log line while the
solution serves. A file stating otherwise would send an agent toward the
silent absence the rules exist to prevent, so the exception is now stated
as the dangerous path it is.

The exported surface was also enumerated partially, omitting Manifest,
Handler, RequestHandler and the exported constants — read as exhaustive,
it would let a breaking change ship without a bang.

Also drops an invented rationale for CI's test timeout and records the
stale v0.0.2 Release object rather than implying tags are the only artifact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor Author

Self-review of this diff (three passes, on the premise that agent-context files are followed literally). Two blockers found and fixed in 5ae0758; both were mine.

1. The file asserted a safety property the runtime does not have. It said boot configuration is resolved in loadConfig, checked in validate(), "refused loudly at boot when unresolved", and told the reader not to read the environment from the interior. registerConsumedAPIs reads os.Getenv(manifest.APIConsumesEnvironmentVariable) at solution.go:543, at serve time; validate() never sees it, and a malformed projection is not refused — ParseConsumedAPIs returns no entries, the runtime logs that the federation is disabled and serves on, so every consumed facade 404s at the gateway while the solution looks healthy (solution.go:544-551).

That is the same "boots, serves, and is simply absent" shape rule 1 tells the story about, which is what made it a blocker rather than a wording nit: an agent adding configuration on that path would have believed a bad value fails the boot, or would have "fixed" solution.go:543 into loadConfig to satisfy a doc. The exception is now stated as the dangerous path it is.

2. The exported surface was enumerated partially but reads as exhaustive. The list named the calls and omitted Manifest, Handler, RequestHandler, Server and four exported constants — Manifest being the one type every solution author writes. An agent adding a required field to it, checking the list, and finding it absent ships a breaking change without a !. Replaced with go doc -short . as the instruction, which cannot drift.

Two smaller corrections in the same commit: "hence the 5m timeout" was an invented rationale (I measured the two wall-clock tests; I never established why CI picked 5m), and the release line now records that a stale GitHub Release object for v0.0.2 is still marked Latest while tags run to v0.0.9.

Checked and refuted, so deliberately not changed: the assetsDir default "../fe-remote/dist" (solution.go:303) does not contradict rule 4, which is scoped to addresses, ports and credentials; the gateway:8080 / gw.example.com URLs in the tests are not external dials, they sit in loadConfig/validate() string tests that never open a socket.

Not examined: the runtime's own code for defects — this diff adds no behaviour, so a docs error's blast radius is an agent's future decisions, which is where I spent the passes instead. Hermeticity is verified statically, not by severing the network. And no consumer of this module was verified to exist, so the intro now says "consumed as the Go module …" rather than naming consumers I did not check.

File is 152 lines, within the standard's ~150 guidance and well under the ~200 cap.

The file now tells an agent that boot configuration is resolved in
loadConfig and refused by validate(), with one serve-time exception whose
failure is a log line rather than a refusal. That claim was prose with
nothing holding it: a second interior read would make the file quietly
wrong again, which is the defect the file was just corrected for.

The guard is structural rather than a list of function names — an
enumeration rots the same way the exported-surface list did. It asserts
every environment read sits in loadConfig's call tree, where validate()
governs the result, or is the documented exception; that the exception
still reads the environment and is still unreachable from loadConfig; and
that this file still names it.

Proven red three ways before landing: an os.Getenv added to a serve-path
handler, the exception's name removed from AGENTS.md, and the exception's
own read replaced by a constant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor Author

Follow-up: the correction in 5ae0758 left a code invariant stated in prose with nothing holding it, which is how the file became wrong in the first place. bd58d23 pins it. CI green (42s).

environment_boundary_test.go parses the package with go/ast and asserts three things: every function reading os.Getenv/LookupEnv/Environ is reachable from loadConfig in the intra-package call graph or is the documented exception; registerConsumedAPIs still reads the environment and is still not reachable from loadConfig; and AGENTS.md still names it. A second serve-time read now fails the suite until the file describes it.

Why structural rather than a list of names. My first version was a hand-written allow-list, and it immediately failed on discoverHostModule (solution.go:168), which scans os.Environ() for injected CODEFLY__ENDPOINT__* carriers — legitimate boot resolution, reached from loadConfig via resolveGateway → hostAddress (solution.go:216). The doc was right and my roster was incomplete: the same failure class as the partial exported-surface enumeration this PR had just replaced with go doc -short .. Worth noting that my review's own env-read scan had the same hole — it grepped os.Getenv, env( and os.LookupEnv, never os.Environ — so the guard found a gap in the method that produced the finding.

Proven red three ways before landing, one probe per assertion, each reverted with git checkout --:

  • _ = os.Getenv("PROBE_INTERIOR_READ") added to handleCapabilities → fails naming handleCapabilities
  • registerConsumedAPIs removed from AGENTS.md → fails naming the file
  • the exception's own read replaced by a constant → fails saying the documented exception no longer exists

A gate proven red one way can be inert on its other branches, which is why each got its own probe.

Not done, and not claimed: the portable checks from obin-ai/module-document-store#290 — cited paths resolve from the repo root, a go/npm line stands in a directory holding the matching manifest, the line cap, CLAUDE.md still a pointer — are not ported here. I verified all of those by hand this session, so there is no live defect, only recurrence risk. That gate is fleet-level work, not repo-level, and this invariant does not substitute for it.

@antoinetoussaint-byte
antoinetoussaint-byte merged commit 0a997ca into main Sep 22, 2026
1 check passed
@antoinetoussaint-byte
antoinetoussaint-byte deleted the issue-30-adopt-the-fleet-agent-context-standard-agents-md branch October 25, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adopt the fleet agent-context standard (AGENTS.md + Agent Skills)

1 participant