Files
marketplace/cli/internal/wire/AGENTS.md
T
naudachu 01fb5a2703 feat: publish releases with this repository's own SDK code
There is no CI: the instance has no act_runner and none is planned, so releases
are cut by hand. That makes `make check` the only thing standing between a
mistake and the tracker, and it is one command: gofmt, vet, the suite with the
cache defeated, `go mod verify`, a vendored build, and `kettle gen skills
--check`. The last one is the invariant worth having — the plugin's SKILL.md
command reference is generated from the binary's registry, so a flag that
changed cannot ship with documentation that recommends the old one.

`cli/cmd/release` publishes to Gitea using the same SDK the binary already
vendors, which is a pleasing thing to be able to say: nothing third-party
handles the artifacts. It is a second binary rather than a `kettle` subcommand
on purpose — `kettle`'s command tree is what generates the plugin's skills, so a
verb there ships to every operator, and publishing a release is build
infrastructure. It is idempotent end to end: an existing release for the tag is
reused, an asset of the same name is replaced rather than doubled, and a retried
run converges instead of duplicating.

`make release` refuses three things, each with its own message: a dirty working
tree, a TAG that is not what `git describe` reports, and a tag the remote does
not have. A release built from uncommitted code is unreproducible and nobody
finds out until they need to reproduce it.

`kettle version` reports the stamp, the toolchain and the VCS revision. The
default is `dev`, and a hand build says so and means it — a binary out of
somebody's working tree is not a release and must not claim to be one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 01:01:27 +05:00

3.2 KiB

AGENTS.md — internal/wire (ADDRESSES)

How this project addresses one repository and one issue, and nothing else. Two types, Repo and Key, and the parsing that reads them.

Imports the standard library and nothing else — no HTTP, no filesystem, no configuration, no SDK, and above all not issue. An identifier that reached for any of those would drag every user of it into that layer. Two tests hold it, see internal/AGENTS.md.

file what is in it
key.go Repo, Key, ParseRepo, ParseKey, Key.In, and the String methods
key_test.go every spelling above, and what a malformed one answers
layering_test.go the two tests that keep this package at the bottom

Four spellings, one address

wire.ParseKey("42")               // Key{Number: 42} — repo zero: "this project's"
wire.ParseKey("#42")              // the same, copied out of a body
wire.ParseKey("owner/repo#42")    // qualified, out of the ledger
wire.ParseKey("https://git.example.com/owner/repo/issues/42")

All four because all four are what somebody has in hand — a number from a receipt, a #42 copied out of an issue body, a qualified key out of the ledger, a URL pasted from a browser. Refusing three of them buys nothing.

Key.Repo is zero when the caller named a number and nothing else, which is the common case on a command line: 42 means "42 in this project's repository", and which repository that is, is the client's business. Key.In(repo) fills it in. Repo.Zero() requires both halves — half a name addresses nothing.

Why a key is not a bare number

Key has to survive being written to a file and read back: it is what the number → slug ledger is keyed by and what the gitea: metadata field holds. A number is ambiguous the moment a dependency lives in another repository, and dependencies are allowed to. So a key is a repository and a number, always, and String() spells it owner/repo#42.

Why this package still exists after the SDK

The JSON shapes used to live here too, because the transport and the bridge both had to name a Gitea issue and neither may import the other. They are code.gitea.io/sdk/gitea's now.

What the SDK has no answer for is addressing. It takes an owner, a name and an int64, and never parses. So the parsing stays, and so does the pair of types it produces — the values that go into the ledger, into the gitea: field, and into every receipt. The longer version of that history is in internal/AGENTS.md.

What does not belong here

Anything that does something with an address: fetching, storing, resolving a repository from configuration. This package parses and prints. Callers are gitea, mapping and cmd.

Keeping this file true

  • Scope: key.go and its tests — the two types and the spellings they accept.
  • Update it when a spelling is added or dropped, a type gains a field, or the zero-value meaning of Key.Repo changes.
  • Do not add a third type here without an argument for why it is an address. Anything that is a payload belongs to the SDK; anything that is a fact about work belongs to the domain.