feat(standard): §15.4/§15.5 — agent work log — v2.04 - #38
Conversation
§15.2 records who maintains an artifact and §15.3 whose work it stands on. Neither records what produced it. §15.4 obligates that record and §15.5 specifies its form: an append-only `.agent-log.jsonl` at the repository root, one line per completed task, written by the harness. A v1.50 draft of §15.4 required a committed table (AUTHORS.md, or a closing "Authoring Model" section) written once per artifact. That mechanism is not what ships. The log is per-task, structured, and git-ignored — and §15.4 states the cost plainly rather than leaving a reader to find it: the record never reaches a clone and makes no published claim. It serves the working copy that produced the work. The Co-Authored-By trailer is compared and kept. §15.4 faults it for being unstructured, for being lost to squash-merges and the rewrites §6.3 permits, and for naming a product without reasoning effort, provider, harness, or any measurement — not for recording activity, which the log does too. Schema: six required fields (task_id, timestamp, model, provider, harness, files_touched), six optional. provider and harness are required because the rationale turns on the combination of the three being what makes a result reproducible. reasoning_effort is its own field rather than folded into the model identifier. Timestamps are UTC + Z, which §14.3 already required of jsonl output. The harness writes the log, not the model: token counts are not observable by a model during its own session, so a field the harness cannot determine is omitted, never estimated. A reference SessionEnd hook is included and was run against a real transcript; it records in-repo paths relative and out-of-repo paths absolute, a relative path escaping the root resolving nowhere once the working copy moves. §15 menu gains two entries; §16 gains one checklist bullet, N/A for hand-written artifacts. §15.1–§15.3 unchanged. No project conforming at v2.03 becomes non-conformant at v2.04. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7991c04a8d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for upstream skill changes, registry updates (§2.1, §15.1), factual corrections | ||
| to normative content, and brand/identity changes. | ||
|
|
||
| - **v2.04 (2026-09-14):** **§15.4 and §15.5 added — what produced an artifact becomes a machine-readable local record.** §15 has carried two attribution axes since the standard's early versions: §15.2 records who maintains an artifact, §15.3 records whose work it stands on. Neither records *what produced it*. When a model drafts a PRD, an implementation plan, or a task list — or codes a project outright — which model, at what reasoning effort, served by which provider, driven by which harness is knowledge that lives in the maintainer's memory of the session and decays within days. **§15.4 obligates a record; §15.5 specifies its form.** The form is an append-only JSON Lines log, **`.agent-log.jsonl`** at the repository root, one line per completed task. A draft of this section existed at v1.50 and was never landed; it required a *committed* table (an `AUTHORS.md`, or a closing `Authoring Model` section) written once per artifact. **That mechanism is not what ships.** The log is per-task rather than per-artifact, structured rather than prose, and **git-ignored rather than committed** — and the section says plainly what that costs: the record never reaches a clone and makes **no published claim** about the artifact. It serves the working copy that produced the work, answering what the maintainer can ask months later about which configuration did what, how often tests passed first try, and what the work cost. An artifact that must tell *consumers* who stands behind it still uses §15.2, unchanged. The `Co-Authored-By:` trailer is compared and kept: §15.4 faults it for being unstructured, for being lost to squash-merges and the history rewrites §6.3 permits, and for naming a product without the reasoning effort, provider, harness, or any measurement — **not** for recording activity, which is precisely what the log does too. The two are independent and both may be used. **Schema:** six required fields (`task_id`, `timestamp`, `model`, `provider`, `harness`, `files_touched`) and six optional (`reasoning_effort`, `subagent_role`, `test_pass_first_try`, `iterations`, `tokens_in`, `tokens_out`); unknown fields are permitted. `provider` and `harness` are required because §15.4's rationale turns on the combination of the three being what makes a result reproducible — the model alone does not. `reasoning_effort` is its own field rather than being folded into the model identifier, JSON having real fields where a table cell did not. Timestamps are RFC 3339 UTC + `Z`, which §14.3 already required of all `jsonl` output. **The harness writes the log, not the model**, and the section explains why: token counts are not observable by a model during its own session, and a model told to report them supplies plausible invented numbers — so **a field the harness cannot determine is omitted, never estimated**, an absent field being a truthful statement that the value is unknown. A reference `SessionEnd` hook is given that reads the real transcript. §15.5 also states the `.gitignore` entry is required and that the log SHOULD be excluded from agent file context, and notes explicitly that none of this conflicts with §5.7's requirement that `AGENTS.md` and `CLAUDE.md` be *tracked* — those carry project knowledge a fresh clone needs, the log is local measurement a fresh clone has no use for. **Unchanged:** §15.1–§15.3 in full, the §15.2 attribution block, the existing trailer convention, and §4.3 licensing metadata — a §15.4 record is a production fact, not legal authorship, and MUST NOT appear in an `SPDX-FileCopyrightText` tag, a `# Maintainer:` line, or `--version` output. The §15 chapter menu gains two entries and §16 gains one checklist bullet, marked N/A for hand-written artifacts. No project conforming at v2.03 becomes non-conformant at v2.04. This is the Standard side; the skill encoding syncs at the same version and date. |
There was a problem hiding this comment.
The raw commit object for 153c5bcba2ae3f6cba8fbe7f7de788de82c672ba has no gpgsig header, so it cannot receive the required Verified status. Recreate this proposed commit with the maintainer's cryptographic signature before it is accepted.
AGENTS.md reference: AGENTS.md:L90-L90
Useful? React with 👍 / 👎.
| @c %**end of header | ||
|
|
||
| @set VERSION 2.03 | ||
| @set VERSION 2.04 |
There was a problem hiding this comment.
Update the settitle version to 2.04
This changes @set VERSION to 2.04 while line 8 still declares @settitle The Steelbore Standard 2.03, so generated formats that consume @settitle retain the previous release number even though the document body and changelog identify v2.04. The release policy explicitly requires all three version-bearing header lines to be updated together.
AGENTS.md reference: AGENTS.md:L70-L70
Useful? React with 👍 / 👎.
| @strong{Reference implementation.} A Claude Code @code{SessionEnd} hook, | ||
| treating one session as one task. It reads the real transcript rather | ||
| than asking the model anything, and omits @code{model} if the transcript | ||
| never names one: |
There was a problem hiding this comment.
Keep the reference output compliant when model is absent
When the transcript never names a model—the scenario explicitly handled here—the implementation leaves model as None and filters it out before writing, but the schema above declares model required and says every required field MUST appear on every line. Copying this reference therefore produces a nonconforming log for that case; either make the field optional or decline the append until a truthful model value can be obtained.
Useful? React with 👍 / 👎.
| with open(os.path.join(ev["cwd"], ".agent-log.jsonl"), "a", | ||
| encoding="utf-8") as fh: |
There was a problem hiding this comment.
Resolve the repository root before writing the log
When the hook event's cwd is a directory below the repository root, this writes .agent-log.jsonl into that subdirectory and computes files_touched relative to it, contradicting the section's repository-root location and repository-relative path contract. Resolve the Git worktree root first and use that root for both the output path and path normalization.
Useful? React with 👍 / 👎.
…2.04 (#70) Skill encoding of the Standard change landing as Spacecraft-Software/Standard#38, at the same version and date. §15.4 obligates a record of what produced an artifact; §15.5 specifies its form — an append-only `.agent-log.jsonl` at the repository root, one line per completed task, written by the harness. Replaces the never-landed v1.50 draft's committed-table mechanism (AUTHORS.md / a closing "Authoring Model" section). The log is per-task, structured, and git-ignored; §15.4 states that cost outright — the record never reaches a clone and makes no published claim. §15.2 remains the mechanism for anything aimed at consumers. Six required fields (task_id, timestamp, model, provider, harness, files_touched) and six optional. provider and harness are required because the rationale turns on the combination of the three being what makes a result reproducible. Timestamps are UTC + Z per §14.3. The harness writes the log, not the model — token counts are not observable by a model mid-session, so a field the harness cannot determine is omitted, never estimated. The reference SessionEnd hook is byte-identical to the Standard's copy. The frontmatter description takes only the version bump: it sits at 994/1000 against the §5.6 cap, and its section enumeration is illustrative rather than exhaustive. Both bundles rebuilt in this commit. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
What
§15 records who maintains an artifact (§15.2) and whose work it stands on (§15.3). Nothing records what produced it. §15.4 obligates that record; §15.5 specifies its form — an append-only
.agent-log.jsonlat the repository root, one line per completed task, written by the harness.Revives the never-landed v1.50 draft on
feat/standard-15-4-authoring-model-attribution(no PR was ever opened), with the mechanism replaced.Mechanism change from the v1.50 draft
The draft required a committed table — an
AUTHORS.md, or a closingAuthoring Modelsection — written once per artifact. That is not what ships. The log is per-task, structured, and git-ignored.§15.4 states the cost rather than leaving a reader to find it: the record never reaches a clone and makes no published claim about the artifact. It serves the working copy that produced the work. Anything aimed at consumers still goes through §15.2, unchanged.
Two internal-consistency fixes came with that:
Co-Authored-Bycritique is recast. The draft faulted trailers for recording activity rather than provenance; a per-task log is activity too. The fault is now structure and completeness — unstructured, lost to squash-merges and the rewrites §6.3 permits, and naming a product without reasoning effort, provider, harness, or any measurement. The trailer convention is kept; the two are independent.Schema
Required:
task_id,timestamp,model,provider,harness,files_touched. Optional:reasoning_effort,subagent_role,test_pass_first_try,iterations,tokens_in,tokens_out. Unknown fields permitted.providerandharnessare required because §15.4's rationale turns on the combination of the three being what makes a result reproducible — the model alone does not.reasoning_effortis its own field rather than folded into the model identifier; JSON has real fields where a table cell did not.Timestamps are UTC +
Z, which §14.3 already required of alljsonloutput.The harness writes it, not the model
Token counts are not observable by a model during its own session, and a model told to report them supplies plausible invented numbers. So the log is harness-generated, and a field the harness cannot determine is omitted, never estimated — an absent field is a truthful "unknown"; a guessed one silently corrupts every later query.
A reference Claude Code
SessionEndhook is included.Verification
make md html infobuilds clean, no warnings..html/.infoare gitignored by design; only.mdis tracked.Z.os.path.relpathturned a file edited outside the repo into a../../../../../../etc/...chain, contradicting §15.5's "repository-relative paths". Fixed in both the implementation and the prose: in-repo paths relative, out-of-repo absolute.Scope
§15.1–§15.3 unchanged. §15 menu gains two entries; §16 gains one checklist bullet, N/A for hand-written artifacts. No project conforming at v2.03 becomes non-conformant at v2.04.
Construct-side skill encoding lands as its own PR at the same version and date.
🤖 Generated with Claude Code