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
31 changes: 17 additions & 14 deletions packages/gittensory-miner/docs/coding-agent-driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ The interface itself lives in `@jsonbored/gittensory-engine`
([`packages/gittensory-engine/src/miner/coding-agent-driver.ts`](../../gittensory-engine/src/miner/coding-agent-driver.ts));
the orchestration around it (mode gating, invocation, the factory) lives in the sibling modules described below.

> **See also:** [Observing your miner](observability.md) — point Grafana at the miner's local SQLite ledgers
> (attempt log, prediction ledger) to see what the driver actually did.

## Why a seam, and why this shape

The design deliberately mirrors the review stack's `SelfHostAi` (`src/selfhost/ai.ts`) rather than inventing a new
Expand All @@ -23,18 +26,18 @@ autonomous continue/stop decisions — the task handed to a driver is already sc

```ts
type CodingAgentDriverTask = {
attemptId: string; // stable id for this attempt (keys the attempt log)
workingDirectory: string; // the ONLY directory a driver may edit (see worktree isolation below)
attemptId: string; // stable id for this attempt (keys the attempt log)
workingDirectory: string; // the ONLY directory a driver may edit (see worktree isolation below)
acceptanceCriteriaPath: string; // path to the immutable acceptance-criteria file written before the run
instructions: string; // the metadata-only prompt (no source contents)
maxTurns: number; // hard cap on agent iterations for this attempt
instructions: string; // the metadata-only prompt (no source contents)
maxTurns: number; // hard cap on agent iterations for this attempt
};

type CodingAgentDriverResult = {
ok: boolean;
changedFiles: readonly string[];
summary: string;
transcript?: string; // opaque provider transcript for operator inspection
transcript?: string; // opaque provider transcript for operator inspection
turnsUsed?: number;
error?: string;
};
Expand All @@ -53,15 +56,15 @@ Agent-SDK driver (#4267) — register in `createCodingAgentDriver` as `claude-cl

A driver never runs in isolation. The neighborhood it plugs into:

| Concern | Module | What it provides |
|---|---|---|
| Execution mode | `coding-agent-mode.ts` | `paused` / `dry_run` / `live` with deny-toward-safety precedence; `codingAgentModeExecutes(mode)` is the single "should this attempt actually spawn?" boolean. A `dry_run` is a pure no-op at the driver boundary. |
| Invocation | `coding-agent-invoke.ts` | `invokeCodingAgentDriver(driver, task, mode?, log?)` — gates on the mode, calls `driver.run`, and streams lifecycle events to an `AttemptLogSink`. |
| Factory | `driver-factory.ts` | `createCodingAgentDriver(options)` resolves a driver by configured name; `resolveConfiguredCodingAgentDriverNames` / `isConfiguredCodingAgentDriver` deny unknown names by default; `runCodingAgentAttempt(options)` is the top-level "resolve + invoke" convenience. |
| Attempt log | `attempt-log.ts` (#4294) | `ATTEMPT_LOG_EVENT_TYPES` + `normalizeAttemptLogEvent` + `createAttemptLogBuffer` + `formatAttemptLogJsonl` — an append-only, JSONL-exportable event trace per attempt, independent of any driver's own transcript. Durable persistence: `packages/gittensory-miner/lib/attempt-log.js` (sibling SQLite store; imports the engine normalizer). |
| Metering | `attempt-metering.ts` (#4311) | `accumulateAttemptUsage` / `meterAttemptUsage` / `evaluateAttemptBudget` over `AttemptBudgetAxis` (`tokens` / `turns` / `wallClockMs` / `costUsd`). |
| Acceptance criteria | (#4271) | The immutable criteria file at `task.acceptanceCriteriaPath`, written before the driver starts. |
| Worktree isolation | (#4269) | Each attempt's `task.workingDirectory` is a dedicated git worktree; a driver must never edit outside it. |
| Concern | Module | What it provides |
| ------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Execution mode | `coding-agent-mode.ts` | `paused` / `dry_run` / `live` with deny-toward-safety precedence; `codingAgentModeExecutes(mode)` is the single "should this attempt actually spawn?" boolean. A `dry_run` is a pure no-op at the driver boundary. |
| Invocation | `coding-agent-invoke.ts` | `invokeCodingAgentDriver(driver, task, mode?, log?)` — gates on the mode, calls `driver.run`, and streams lifecycle events to an `AttemptLogSink`. |
| Factory | `driver-factory.ts` | `createCodingAgentDriver(options)` resolves a driver by configured name; `resolveConfiguredCodingAgentDriverNames` / `isConfiguredCodingAgentDriver` deny unknown names by default; `runCodingAgentAttempt(options)` is the top-level "resolve + invoke" convenience. |
| Attempt log | `attempt-log.ts` (#4294) | `ATTEMPT_LOG_EVENT_TYPES` + `normalizeAttemptLogEvent` + `createAttemptLogBuffer` + `formatAttemptLogJsonl` — an append-only, JSONL-exportable event trace per attempt, independent of any driver's own transcript. Durable persistence: `packages/gittensory-miner/lib/attempt-log.js` (sibling SQLite store; imports the engine normalizer). |
| Metering | `attempt-metering.ts` (#4311) | `accumulateAttemptUsage` / `meterAttemptUsage` / `evaluateAttemptBudget` over `AttemptBudgetAxis` (`tokens` / `turns` / `wallClockMs` / `costUsd`). |
| Acceptance criteria | (#4271) | The immutable criteria file at `task.acceptanceCriteriaPath`, written before the driver starts. |
| Worktree isolation | (#4269) | Each attempt's `task.workingDirectory` is a dedicated git worktree; a driver must never edit outside it. |

## Authoring a third driver

Expand Down
52 changes: 52 additions & 0 deletions packages/gittensory-miner/docs/observability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Observing your miner

How to point Grafana at a running miner's local SQLite ledgers to see its attempt and prediction history. This
covers the **miner-specific** observability wiring only; for general self-host operations, see your ops runbook.

## What's observable

The miner writes append-only SQLite ledgers under `GITTENSORY_MINER_CONFIG_DIR` (default
`~/.config/gittensory-miner` on a laptop, or `/data/miner` in the fleet Docker image — see
[`DEPLOYMENT.md`](../DEPLOYMENT.md)):

- **`attempt-log.sqlite3`** — the driver-level attempt event trace (event type, action class, mode, reason,
timestamps), table `attempt_log_events`.
- **`prediction-ledger.sqlite3`** — recorded predicted-gate verdicts for later scoring.

## Point Grafana at the ledgers

The repo ships datasource provisioning at
[`grafana/provisioning/datasources/ams-ledgers.yml`](../../../grafana/provisioning/datasources/ams-ledgers.yml)
— two **read-only** `frser-sqlite-datasource` entries: `AMS Attempt Log` (uid `ams-attempt-log`) and
`AMS Prediction Ledger` (uid `ams-prediction-ledger`).

1. **Install the SQLite plugin** in Grafana — the same one the maintainer `GittensoryDB` datasource uses:

```sh
GF_INSTALL_PLUGINS=frser-sqlite-datasource
```

2. **Mount your ledger directory** into the Grafana container, read-only, at `/ams-ledgers` so the provisioned
`path:` values resolve (the `:ro` mount plus the query-only plugin mean Grafana can never write the live
ledgers):

```yaml
# in your Grafana service (docker-compose)
volumes:
- "${GITTENSORY_MINER_CONFIG_DIR:-~/.config/gittensory-miner}:/ams-ledgers:ro"
```

The two datasources point at `/ams-ledgers/attempt-log.sqlite3` and `/ams-ledgers/prediction-ledger.sqlite3`.
If you mount elsewhere, edit the two `path:` values in `ams-ledgers.yml` to match.

3. **Restart Grafana.** The two datasources appear under **Connections → Data sources**, already provisioned
(non-editable) so they survive restarts.

## Load a dashboard

Dashboards live in [`grafana/dashboards/`](../../../grafana/dashboards/) and are auto-provisioned from that
directory. To visualize the ledgers, add an AMS dashboard JSON there — or import one at runtime via the Grafana
UI (**Dashboards → Import**) — and point its panels at the `AMS Attempt Log` / `AMS Prediction Ledger`
datasources above. Panels query the ledger tables directly (e.g. `SELECT * FROM attempt_log_events`); the
`frser-sqlite-datasource` plugin also supports `json_extract(payload_json, '$.…')` to read fields nested inside
an event's payload.