Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/atlas/assets/seed/catalog.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"citations":[{"path":"src/FS.GG.Coord.Core/Telemetry.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"cfe7eb7d4e26dff2e220d8e87bfe13d2a2e122349d275df6371f53d42d6a81bf"},{"path":"src/FS.GG.Coord.Cli/SkillTelemetryReaders.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"2e48229f7e48ea3c52017073e30b36daf48ee529771b91e3eb002d1c66bdd29b"},{"path":"src/FS.GG.Coord.Core/TelemetryStore.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"0f852fd75475cae72e9b1b09213a6cf11fa86d58377e06eca652396d26feb402"},{"path":".claude/skills/pnext-item/references/lifecycle-ledger.md","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"566c863a46c7e5fce98c439e421e8651c1070a84b369655e193d14638dcf0100"},{"path":"tests/FS.GG.Coord.Core.Tests/TelemetryTests.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"dd2c3a3133ce186712f8ed5535f65410ed0202de06b33a56318daf58a02b5078"}],"conflictsWith":[],"id":"github/claude-transcript-native-usage","kind":"lesson","recordedAt":"2026-10-22T04:21:44Z","repository":"FS-GG/.github","schema":"fsgg.atlas/1","status":"recorded","summary":"Source for #4801 (unmerged at capture) reads Claude Code transcript JSONL through the existing usage and passive paths without a new wire schema: `telemetry usage collect claude --session-file` uses the Codex --turn-id/--all-responses/--since/--until contract, and a fsgg.telemetry.passive-selection/1 file naming claudeHome feeds provider-usage-observation/1 with provenance claude-local-transcript/1 and identity namespace claude-transcript/1. The legacy --snapshot input stays; nothing produces it by default.\n\nMeasured on one host, Claude Code 2.1.299 (shape only; no transcript content retained): usage repeats per content block. The main-thread writer emits only completed records (stop_reason set) with identical usage. The subagent writer streams; per-block records carry stop_reason null and provisional output_tokens without thinking_tokens before one completed record, and 11 of 17 message ids disagreed. Deduplicate on completed records only, and refuse when completed repeats disagree. A response with no completed record is withheld and makes later totals in its turn unknown, never zero. Every user record, including tool results, carries promptId. Assistant records do not, so turn_id is the promptId of the nearest preceding user record at completion; this agreed with parentUuid resolution for all 209 measured records. In a subagent transcript promptId tracks the session's current prompt rather than the subagent task. Subagent transcripts were observed at <session>/subagents/agent-<agentId>.jsonl beside a .meta.json, sharing the parent sessionId with isSidechain true and agentId. Readers take an explicit file and give each sidechain a derived version-8 thread identity; the path is an observation, not a contract. The passive cursor retains the prompt context so resumed passes attribute like a full read; its digest excludes per-block timestamps so identical repeats are not corrections.\n\nUnknown: whether status-line payloads still carry prompt_id/timestamp; older transcripts lacking promptId, isSidechain or agentId fail closed. --since/--until compare timestamps ordinally, so 05:01:30.000Z sorts before 05:01:30Z, as with Codex. Receiver admission of the new provenance needs a Host built from this source. Installed adoption, Host ingestion and display remain with #4640.","supersedes":[],"tags":["telemetry","claude","transcript","usage","passive","subagent","dedupe","parity","fail-closed"],"title":"Claude Code native usage comes from completed transcript records, not status-line snapshots"}
33 changes: 22 additions & 11 deletions .agents/skills/pnext-item/references/lifecycle-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Each JSONL line is one phase transition. The shared v1 fields are `schema_versio
- `tooling` binds `ledger_schema` plus `runtime`, `coordination`, `sdd`, and `contracts` components.
Each component records its exact name/version/source or an explicit `unavailable`/`not_applicable`
reason. For Codex, take the runtime version from `session_meta.cli_version`; for Claude Code, take it
from status-line `version`. Capture `fsgg-coord --version`, `fsgg-sdd --version`, and the governed
from the transcript assistant record's `version`. Capture `fsgg-coord --version`, `fsgg-sdd --version`, and the governed
contracts version at phase start. Historical comparisons must group by the canonicalized `tooling`
object; do not blend durations or token rates from different toolchain fingerprints.
- `model` records `provider`, exact `name`/variant, optional `effort`, and authoritative `source`. A model
Expand Down Expand Up @@ -121,15 +121,25 @@ Never append another phase to a receipt whose SHA-256 is already cited. The vali
The local Codex JSONL is an internal interface, so the collector validates every required key and fails
closed on shape drift. For direct API work, prefer the stable response `usage` object.

Claude Code exposes `session_id`, `prompt_id`, `model.id`, effort, and the latest API response's input,
cache-creation, cache-read, and output usage to a status-line command. Persist those snapshots after each
assistant message. A `Stop` hook runs after the main response finishes and receives `session_id` and
`transcript_path`; use it to append the saved snapshot. `SubagentStop` supplies a separate
`agent_transcript_path`, so subagent usage must remain separate. The collector derives a stable response
identity from session, prompt, timestamp, model, and usage, so repeated hook delivery is idempotent. The status-line value is one latest API
response, not a whole multi-call turn; aggregate only captured requests. Claude's ordinary usage does not
separate reasoning from output, so the report leaves `reasoning` empty rather than guessing. For
non-interactive work, `--output-format json`/`stream-json` or the Agent SDK result is preferred.
Claude Code persists its transcript as JSONL under `~/.claude/projects/<project>/<session>.jsonl`. Collect
it with the same selection contract; no status line or hook is required:

```sh
scripts/fsgg-coord telemetry usage collect claude \
--session-file <transcript.jsonl> --task <item/phase> --turn-id <prompt-id> \
--coord-version <version> --sdd-version <version> --contracts-version <version> \
--all-responses --append <private-untracked-phase-usage.csv>
```

The collector emits one row per distinct API response, keyed by `message.id`. It deduplicates the
per-content-block records and binds `requestId`, model, effort, version and timestamp. Input is uncached
plus cache-read plus cache-creation; `reasoning` is `thinking_tokens` only when the response reports it.
`turn_id` is the `promptId` of the nearest preceding user record; turn totals accumulate within that
thread and prompt, and thread totals stay empty. A sidechain record keeps its own derived thread. Disagreeing
repeated usage, malformed or partial lines, oversized input, missing counters and incomplete streaming
responses (`stop_reason` null) are refused, never counted as zero. Collect after the response completes,
or bound a live transcript with `--until`. Public provenance is `claude-transcript-jsonl:sha256:<digest>`.
The legacy `--snapshot` status-line input remains accepted, but nothing produces it by default.

### Supervising a completed child

Expand All @@ -147,7 +157,8 @@ terminal, then:

For Codex, a parent may use a unique phase marker only when the child could not return the session/turn
identity; multiple matching sessions are an attribution failure, not permission to choose one. For
Claude Code, consume the `SubagentStop` `agent_transcript_path`, never the parent's transcript. A strict
Claude Code, collect the subagent's own transcript, never the parent's; observed hosts write it beside the
session as `<session>/subagents/agent-<agent-id>.jsonl`. A strict
post-completion lookup that finds no unique terminal record, or a collector failure caused by internal
schema drift, may seal `unavailable` only when the exact lookup and validation failure are recorded.
“Final usage is written after this response” proves the state is pending and is forbidden as an
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/publishing-and-deployment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Registry release inventory: 18 package-bearing contracts across 9 producers; 16
| `game` | `game-scene-adapter` | `0.17.0` | `0.17.0` | `game:0.17.0` | FS.GG.Game.Render package — Adapter (sim-state -> FS.GG.UI.Scene drawables) |
| `audio` | `fs-gg-audio` | `0.6.0` | `0.6.0` | `audio:0.6.0` | FS.GG.Audio.Core/.Host/.Engine/.Elmish/.WebBrowser public .fsi surfaces — AudioEffect vocabulary + IAudioBackend/IMixingBackend seam + mixing Engine + Audio.Cmd Elmish bridge + browser Web Audio host |
| `net` | `fs-gg-net` | `0.6.0` | `0.6.0` | `net:0.6.0` | FS.GG.Net.Core/.WebSocket/.WebSocket.Server/.Protobuf/.Grpc/.Elmish public .fsi surfaces — ITransport/IMessageChannel seam + Sequential/Multiplexed correlation + serve/ServerEcho + WebSocket client/server transport + Google.Protobuf/protobuf-net codecs + gRPC lifecycle bridge + Elmish Cmd/Sub |
| `github` | `coord-engine` | `0.112.0` | `0.112.0` | `github:0.112.0` | the `fsgg-coord-engine` CLI verb surface (claim/take/batch/who/widen/set-paths/say/landable/done/release/flush/…) + its exit-code contract, emitted from src/FS.GG.Coord.Core/Protocol.fs; shipped as the FS.GG.Coord.Cli dotnet tool |
| `github` | `coord-engine` | `0.113.0` | `0.112.0` | `github:0.112.0` | the `fsgg-coord-engine` CLI verb surface (claim/take/batch/who/widen/set-paths/say/landable/done/release/flush/…) + its exit-code contract, emitted from src/FS.GG.Coord.Core/Protocol.fs; shipped as the FS.GG.Coord.Cli dotnet tool |
| `github` | `telemetry-host` | `0.8.0` | `0.8.0` | `github:0.8.0` | optional Linux x64 FS.GG.Telemetry.Host dotnet tool — authenticated workspace-scoped ingestion, private dashboard, protected native capture and bounded learning export; independently versioned from the github coordination coherent set |
| `github` | `new-sdd-workspace` | `0.21.0` | `0.21.0` | `github:0.21.0` | the `new-sdd-workspace` scaffolder CLI (package FS.GG.NewSddWorkspace) — one-command full-stack SDD workspace creation, wrapping the FS.GG.Templates `rendering` provider (ADR-0016); shipped as a dotnet tool |
| `templates` | `fs-gg-workspace-template` | `0.19.0` | `0.19.0` | `templates:0.19.0` | FS.GG.Workspace.Template package, eight template configurations and seven `dotnet new` selectors: workspace-provider identities — `fs-gg-console` (provider `console` — minimal F# executable, no npm lane, ADR-0072 §2); `fs-gg-web` (provider `web` — F# ASP.NET Core + plain TypeScript/Vite website, ADR-0071 §3); `fs-gg-fable-game` (provider `fable-game` — F# ASP.NET Core + Fable/Elmish game client, SignalR for connection-oriented real-time traffic + plain HTTP endpoints with explicit versioned DTOs for typed request/response per ADR-0073, consuming the published `fs-gg-game-core-fable-lockstep-v1` profile per ADR-0069); `fs-gg-fable-bindings` (provider `fable-bindings` — Fable interop library over an exactly pinned npm package/declaration closure, ADR-0072 §3, first proved by the unreleased EHotwagner/babylonjsBindings reference) — plus `fs-gg-governance`, the separately registered pre-existing governance overlay template folded into this package at the same rename; `fs-gg-project-knowledge` and `fs-gg-python` are also already packaged. The current and legacy fable-game configurations share one selector. |
Expand Down
8 changes: 4 additions & 4 deletions .agents/skills/work-roadmap/references/lifecycle-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ in `source`.

The roadmap driver, as supervising parent, owns every post-child seal. A child returns an unposted
terminal draft with `pending final usage` and its exact session/turn identity (or Claude prompt and
`SubagentStop` transcript path). It does not post its own terminal lifecycle event, because the final
transcript path). It does not post its own terminal lifecycle event, because the final
usage row does not exist until after that response ends. Once the child is terminal, the driver locates
the completed record, runs the strict collector into a phase-scoped immutable receipt, seals the terminal
event as `measured`, and only then accepts the handoff. A statement that final usage will be written after
Expand All @@ -114,9 +114,9 @@ If a legacy immutable event already used the timing excuse, append a separate
`telemetry-reconciliation-<phase>` recovery phase before host acceptance, cycle completion, or Done.

Codex's completed `token_usage_record` rows provide request, turn, and thread totals; matching
`turn_context` rows provide the exact model variant and effort. Claude Code's status-line input provides
the exact model ID and latest-response input/cache/output usage, while `Stop` and `SubagentStop` hooks
provide the post-response lifecycle point and separate transcript paths. The `pnext-item` lifecycle-ledger
`turn_context` rows provide the exact model variant and effort. Claude Code's transcript JSONL provides one
completed usage record per API response (`message.id`) with its exact model and effort; collect it with
`telemetry usage collect claude --session-file`, keeping each subagent's own transcript separate. The `pnext-item` lifecycle-ledger
contract carries the equivalent normal-item collection rules. If turn-level usage spans multiple phases,
do not allocate or estimate shares.

Expand Down
9 changes: 9 additions & 0 deletions .agents/skills/work-roadmap/references/runtime-observation.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ Call the item total proven only after every expected invocation is present, ever
outcome and final completed-turn counters, and every submitted batch has an applied Host receipt. Missing,
pending or conflicting evidence remains an explicit coverage gap; never infer a total from partial counters.

## Claude Code usage

Claude Code has no observed launcher or App Server join. Its native usage reaches the same local path from
an explicitly selected transcript: `fsgg-coord-engine telemetry usage collect claude --session-file` for a
phase receipt, or `telemetry passive capture` with a `fsgg.telemetry.passive-selection/1` file naming
`claudeHome` and the selected transcripts below its `projects` directory. Passive rows use provenance
`claude-local-transcript/1`, partial population and unknown attribution. Subagent transcripts stay separate
files and threads; item totals and attribution remain unknown.

## Record repository-owned dispatches by default

This native collaboration route applies when the opt-in `codex-exec` route above was not selected. The launcher
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/atlas/assets/seed/catalog.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"citations":[{"path":"src/FS.GG.Coord.Core/Telemetry.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"cfe7eb7d4e26dff2e220d8e87bfe13d2a2e122349d275df6371f53d42d6a81bf"},{"path":"src/FS.GG.Coord.Cli/SkillTelemetryReaders.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"2e48229f7e48ea3c52017073e30b36daf48ee529771b91e3eb002d1c66bdd29b"},{"path":"src/FS.GG.Coord.Core/TelemetryStore.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"0f852fd75475cae72e9b1b09213a6cf11fa86d58377e06eca652396d26feb402"},{"path":".claude/skills/pnext-item/references/lifecycle-ledger.md","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"566c863a46c7e5fce98c439e421e8651c1070a84b369655e193d14638dcf0100"},{"path":"tests/FS.GG.Coord.Core.Tests/TelemetryTests.fs","repository":"FS-GG/.github","revision":"9c28aaf574512ec1f1d98e5664cec83e6070e573","sha256":"dd2c3a3133ce186712f8ed5535f65410ed0202de06b33a56318daf58a02b5078"}],"conflictsWith":[],"id":"github/claude-transcript-native-usage","kind":"lesson","recordedAt":"2026-10-22T04:21:44Z","repository":"FS-GG/.github","schema":"fsgg.atlas/1","status":"recorded","summary":"Source for #4801 (unmerged at capture) reads Claude Code transcript JSONL through the existing usage and passive paths without a new wire schema: `telemetry usage collect claude --session-file` uses the Codex --turn-id/--all-responses/--since/--until contract, and a fsgg.telemetry.passive-selection/1 file naming claudeHome feeds provider-usage-observation/1 with provenance claude-local-transcript/1 and identity namespace claude-transcript/1. The legacy --snapshot input stays; nothing produces it by default.\n\nMeasured on one host, Claude Code 2.1.299 (shape only; no transcript content retained): usage repeats per content block. The main-thread writer emits only completed records (stop_reason set) with identical usage. The subagent writer streams; per-block records carry stop_reason null and provisional output_tokens without thinking_tokens before one completed record, and 11 of 17 message ids disagreed. Deduplicate on completed records only, and refuse when completed repeats disagree. A response with no completed record is withheld and makes later totals in its turn unknown, never zero. Every user record, including tool results, carries promptId. Assistant records do not, so turn_id is the promptId of the nearest preceding user record at completion; this agreed with parentUuid resolution for all 209 measured records. In a subagent transcript promptId tracks the session's current prompt rather than the subagent task. Subagent transcripts were observed at <session>/subagents/agent-<agentId>.jsonl beside a .meta.json, sharing the parent sessionId with isSidechain true and agentId. Readers take an explicit file and give each sidechain a derived version-8 thread identity; the path is an observation, not a contract. The passive cursor retains the prompt context so resumed passes attribute like a full read; its digest excludes per-block timestamps so identical repeats are not corrections.\n\nUnknown: whether status-line payloads still carry prompt_id/timestamp; older transcripts lacking promptId, isSidechain or agentId fail closed. --since/--until compare timestamps ordinally, so 05:01:30.000Z sorts before 05:01:30Z, as with Codex. Receiver admission of the new provenance needs a Host built from this source. Installed adoption, Host ingestion and display remain with #4640.","supersedes":[],"tags":["telemetry","claude","transcript","usage","passive","subagent","dedupe","parity","fail-closed"],"title":"Claude Code native usage comes from completed transcript records, not status-line snapshots"}
Loading
Loading