vouchington-tooling 0.24.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +43 -0
  2. package/dist/agent-blackboard/client.d.mts +5 -0
  3. package/dist/agent-blackboard/client.mjs +1 -1
  4. package/dist/agent-blackboard/feedback-audit-source.d.mts +13 -0
  5. package/dist/agent-blackboard/feedback-audit-source.mjs +30 -0
  6. package/dist/agent-blackboard/feedback-compose.d.mts +5 -1
  7. package/dist/agent-blackboard/feedback-compose.mjs +8 -18
  8. package/dist/agent-blackboard/feedback-journal-audit.d.mts +20 -0
  9. package/dist/agent-blackboard/feedback-journal-audit.mjs +29 -0
  10. package/dist/agent-blackboard/feedback-journal-sandbox.d.mts +5 -0
  11. package/dist/agent-blackboard/feedback-journal-sandbox.mjs +40 -0
  12. package/dist/agent-blackboard/index.d.mts +9 -8
  13. package/dist/agent-blackboard/index.mjs +7 -34
  14. package/dist/agent-blackboard/journal.d.mts +21 -0
  15. package/dist/agent-blackboard/journal.mjs +45 -0
  16. package/dist/agent-blackboard/session-tools.d.mts +36 -0
  17. package/dist/agent-blackboard/session-tools.mjs +41 -0
  18. package/dist/cli/commands/mcp.d.mts +5 -0
  19. package/dist/cli/commands/mcp.mjs +18 -0
  20. package/dist/cli/index.mjs +5 -5
  21. package/dist/cli/installed-version.d.mts +1 -0
  22. package/dist/cli/installed-version.mjs +5 -0
  23. package/dist/cli/parse-forwarded-commands.d.mts +3 -0
  24. package/dist/cli/parse-forwarded-commands.mjs +2 -0
  25. package/dist/cli/parse.d.mts +3 -0
  26. package/dist/cli/usage.d.mts +1 -1
  27. package/dist/cli/usage.mjs +6 -0
  28. package/dist/mcp-server/args.d.mts +9 -0
  29. package/dist/mcp-server/args.mjs +48 -0
  30. package/dist/mcp-server/context.d.mts +19 -0
  31. package/dist/mcp-server/context.mjs +23 -0
  32. package/dist/mcp-server/dispatch.d.mts +18 -0
  33. package/dist/mcp-server/dispatch.mjs +62 -0
  34. package/dist/mcp-server/fake-blackboard.test-helpers.d.mts +39 -0
  35. package/dist/mcp-server/fake-blackboard.test-helpers.mjs +75 -0
  36. package/dist/mcp-server/git-fixture.test-helpers.d.mts +16 -0
  37. package/dist/mcp-server/git-fixture.test-helpers.mjs +35 -0
  38. package/dist/mcp-server/handlers-journal.d.mts +6 -0
  39. package/dist/mcp-server/handlers-journal.mjs +98 -0
  40. package/dist/mcp-server/handlers-session.d.mts +4 -0
  41. package/dist/mcp-server/handlers-session.mjs +47 -0
  42. package/dist/mcp-server/harness.test-helpers.d.mts +33 -0
  43. package/dist/mcp-server/harness.test-helpers.mjs +48 -0
  44. package/dist/mcp-server/run.d.mts +20 -0
  45. package/dist/mcp-server/run.mjs +21 -0
  46. package/dist/mcp-server/sdk.d.mts +17 -0
  47. package/dist/mcp-server/sdk.mjs +33 -0
  48. package/dist/mcp-server/server.d.mts +9 -0
  49. package/dist/mcp-server/server.mjs +17 -0
  50. package/dist/mcp-server/tools.d.mts +19 -0
  51. package/dist/mcp-server/tools.mjs +120 -0
  52. package/dist/mcp-server/worktree.d.mts +18 -0
  53. package/dist/mcp-server/worktree.mjs +58 -0
  54. package/dist/session-friction/audit-block.d.mts +4 -0
  55. package/dist/session-friction/audit-block.mjs +45 -0
  56. package/dist/session-friction/ci-failures.d.mts +2 -1
  57. package/dist/session-friction/ci-failures.mjs +10 -46
  58. package/dist/session-friction/journal.d.mts +14 -0
  59. package/dist/session-friction/journal.mjs +66 -0
  60. package/dist/session-friction/report.mjs +10 -74
  61. package/docs/mcp-server.md +134 -0
  62. package/package.json +7 -2
  63. package/skills/blackboard/SKILL.md +59 -22
  64. package/skills/manifest.json +19 -19
  65. package/skills/retrospective-distill/SKILL.md +37 -13
@@ -1,61 +1,8 @@
1
1
  import { eventLimit, readFrictionLog, requireDirectory } from './log.mjs';
2
- import { buildCiFailuresSection, getConformingGroups } from './ci-failures.mjs';
2
+ import { buildCiFailuresSection, getConformingGroups, incompleteCiSection } from './ci-failures.mjs';
3
+ import { errorMessage, scanJournal } from './journal.mjs';
3
4
  import { buildSandboxSection } from './sandbox.mjs';
4
5
  import { validateSessionId } from './session-id.mjs';
5
- const JOURNAL_ENTRY_MAX_COUNT = 500;
6
- const JOURNAL_MARKDOWN_MAX_BYTES = 10_000;
7
- const JOURNAL_TOTAL_MAX_BYTES = 1_000_000;
8
- function journalData(entry) {
9
- try {
10
- const data = entry?.data;
11
- return data ? { type: data.type, markdown: data.markdown } : undefined;
12
- }
13
- catch {
14
- return 'unreadable';
15
- }
16
- }
17
- async function collectEntries(entries) {
18
- const result = [];
19
- let consumed = 0;
20
- let inspectedBytes = 0;
21
- let retainedBytes = 0;
22
- let truncated = false;
23
- for await (const entry of entries) {
24
- consumed++;
25
- const scanned = journalData(entry);
26
- if (scanned === 'unreadable')
27
- truncated = true;
28
- const data = scanned === 'unreadable' ? undefined : scanned;
29
- const markdown = data?.markdown;
30
- if (data?.type === 'journal' && typeof markdown !== 'string')
31
- truncated = true;
32
- if (data?.type === 'journal' && typeof markdown === 'string') {
33
- const bytes = Buffer.byteLength(markdown);
34
- inspectedBytes += bytes;
35
- if (bytes > JOURNAL_MARKDOWN_MAX_BYTES)
36
- truncated = true;
37
- if (bytes <= JOURNAL_MARKDOWN_MAX_BYTES && retainedBytes + bytes <= JOURNAL_TOTAL_MAX_BYTES) {
38
- result.push({ data: { type: 'journal', markdown } });
39
- retainedBytes += bytes;
40
- }
41
- }
42
- if (consumed >= JOURNAL_ENTRY_MAX_COUNT ||
43
- inspectedBytes >= JOURNAL_TOTAL_MAX_BYTES ||
44
- retainedBytes >= JOURNAL_TOTAL_MAX_BYTES) {
45
- truncated = true;
46
- break;
47
- }
48
- }
49
- return { entries: result, truncated };
50
- }
51
- function errorMessage(error) {
52
- try {
53
- return error instanceof Error ? error.message : String(error);
54
- }
55
- catch {
56
- return '[unprintable error]';
57
- }
58
- }
59
6
  function sandboxMarkdown(friction) {
60
7
  if (friction.status === 'events')
61
8
  return `${friction.truncated ? `## Capture Coverage\nStatus: partial\nDropped records: ${friction.droppedCount}\n\n` : ''}${buildSandboxSection(friction.events)}`;
@@ -64,9 +11,6 @@ function sandboxMarkdown(friction) {
64
11
  const status = friction.status === 'empty' ? 'none observed' : 'unavailable (no friction log)';
65
12
  return `## Sandbox & Permission Audit\nStatus: ${status}`;
66
13
  }
67
- function incompleteCiSection(markdownBlocks) {
68
- return ['## CI Failures\nStatus: unavailable (journal scan incomplete)', ...markdownBlocks].join('\n\n');
69
- }
70
14
  function reportFromLog(sessionId, logOptions, journal) {
71
15
  try {
72
16
  const friction = readFrictionLog(sessionId, logOptions);
@@ -113,24 +57,16 @@ export async function buildSessionFrictionReport(sessionId, options) {
113
57
  validateSessionId(sessionId);
114
58
  requireDirectory(options.directory);
115
59
  eventLimit(options.maxEvents);
116
- let journal;
117
- try {
118
- const loaded = await options.journalLoader(sessionId);
119
- if (loaded.status === 'not-found')
120
- journal = { status: 'ok', markdownBlocks: [], truncated: false };
121
- else {
122
- const collected = await collectEntries(loaded.entries);
123
- journal = {
60
+ const scanned = await scanJournal(sessionId, options.journalLoader);
61
+ const journal = scanned.status === 'unreachable'
62
+ ? scanned
63
+ : scanned.status === 'not-found'
64
+ ? { status: 'ok', markdownBlocks: [], truncated: false }
65
+ : {
124
66
  status: 'ok',
125
- markdownBlocks: getConformingGroups(collected.entries),
126
- truncated: collected.truncated,
67
+ markdownBlocks: getConformingGroups(scanned.entries),
68
+ truncated: scanned.truncated,
127
69
  };
128
- }
129
- }
130
- catch (error) {
131
- const diagnostic = errorMessage(error);
132
- journal = { status: 'unreachable', diagnostic };
133
- }
134
70
  const report = reportFromLog(sessionId, options, journal);
135
71
  if (journal.status === 'unreachable') {
136
72
  const diagnostic = report.diagnostic
@@ -0,0 +1,134 @@
1
+ # MCP server
2
+
3
+ `vouchington mcp` serves the [agent-blackboard](../README.md#validated-feedback-and-delivery)
4
+ journal operations to an agent over stdio (Model Context Protocol). An agent passes the markdown as
5
+ a tool argument; there is no temp file, `--file`, or replay command. The server builds on the
6
+ existing `vouchington-tooling/agent-blackboard` exports and adds no provider protocol.
7
+
8
+ Phase 1 of [vouchington-tooling#324](https://github.com/vouchington/vouchington-tooling/issues/324)
9
+ covers the journal, outbox, session, and snapshot tools below. Retrospective and pull request tools
10
+ are later phases.
11
+
12
+ ## Install
13
+
14
+ The server needs three packages next to `vouchington-tooling`. The last two are optional peer
15
+ dependencies, so nothing else in the CLI requires them:
16
+
17
+ ```bash
18
+ pnpm add -D vouchington-tooling agent-blackboard@^0.6.0
19
+ pnpm add -D @modelcontextprotocol/sdk zod
20
+ ```
21
+
22
+ `zod` is required by the SDK. When the SDK is missing, `vouchington mcp` writes a message naming the
23
+ package to stderr and exits with status 1. `agent-blackboard` is resolved from the validated
24
+ worktree at call time (`createRequire` on `<worktree>/package.json`), never from this package.
25
+
26
+ The connection comes from `AGENT_BLACKBOARD_URL` and `AGENT_BLACKBOARD_TOKEN` in the server's
27
+ environment. The server never searches for, prints, or mints them.
28
+
29
+ ## Launch
30
+
31
+ ```bash
32
+ vouchington mcp
33
+ ```
34
+
35
+ The command takes no arguments. Start it inside the repository's git worktree: that repository
36
+ defines which worktrees the tools accept. stdout carries only protocol frames, and diagnostics go
37
+ to stderr.
38
+
39
+ ## Tools
40
+
41
+ Every tool takes an explicit `sessionId` (`^[A-Za-z0-9._:-]+$`, at most 256 characters) that the
42
+ server never infers, and an optional `worktree`. Unknown arguments are rejected. Failures come back
43
+ as MCP tool errors (`isError: true`) with an actionable message rather than crashing the server.
44
+
45
+ | Tool | Arguments besides `sessionId` and `worktree` | Returns |
46
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
47
+ | `journal_append` | `parentSessionId`, `agent`, `version`, `mode` (`interactive` or `autonomous`), `markdown`, `sourceEventId`, `workOutcome`, `repositories`, `feedbackCoverage`, optional `timestamp`, `category` | `sessionId`, `timestamp`, delivery `status` (`delivered` with a verified receipt, or `pending`) |
48
+ | `journal_entries` | none | `sessionId` and `entries`, every entry oldest first |
49
+ | `outbox_status` | none | `sessionId`, `status`, `pendingCount` |
50
+ | `outbox_flush` | none | `sessionId`, `status`, `pendingCount`, `deliveredCount` |
51
+ | `session_ensure` | `parentSessionId`, `agent`, `version` | `sessionId`, `status` (`created` or `exists`), `archived` |
52
+ | `snapshot_export` | optional `agent`, `version`, `parentSessionId`, `data`, `dataArrayContains`, `inactiveForHours` | `sessionId`, `path`, `counts`, `checksum`, `manifest`, `cleanupToken` |
53
+ | `session_archive` | none | `sessionId`, `archived: true` |
54
+
55
+ `journal_append` validates the whole feedback envelope with `validateFeedbackEnvelope` before
56
+ anything is written, so a missing required field writes nothing. It returns the verified read-back
57
+ result of `writeFeedback`. Delivery is at least once. The envelope includes its timestamp, so when
58
+ retrying the same `sourceEventId`, resend the same content and the `timestamp` the first call
59
+ returned; the server fixes a default timestamp and returns it for that reason. Markdown is limited
60
+ to 12000 bytes.
61
+
62
+ `journal_entries` returns `{ sessionId, entries }`. Each entry is exactly what the `agent-blackboard`
63
+ client returns (`sessionId`, `createdAt`, `data`), so `data` keeps its envelope fields such as
64
+ `repositories`, `sourceEventId`, `workOutcome`, and `feedbackCoverage`. Entries of every type come
65
+ back, including `retrospective` and legacy entries without an envelope. The client documents no
66
+ order, so they are sorted stably by `createdAt`, oldest first. An empty session returns
67
+ `entries: []`. `vouchington agent-blackboard journal entries` still prints journal markdown only.
68
+
69
+ `sessionId` on `outbox_status`, `outbox_flush`, and `snapshot_export` only identifies the caller.
70
+ The outbox is per worktree and the status and flush cover every record in it. Flushing an empty
71
+ outbox does not create the directory. `snapshot_export` never accepts a destination: the
72
+ `agent-blackboard` client chooses a private file and returns its path. `session_archive` is the one
73
+ destructive tool; archived metadata is immutable, while entries stay appendable.
74
+
75
+ The outbox lives at `<worktree>/.local/blackboard-outbox` and is used only in interactive mode.
76
+ Autonomous mode forbids a filesystem outbox, so a failed delivery is an error.
77
+
78
+ ## Worktree validation
79
+
80
+ `worktree` must be an absolute path that, after resolving symlinks, exactly matches an entry of
81
+ `git worktree list --porcelain` for the repository the server was launched from. The list is read on
82
+ every call, so worktrees created after launch are accepted and removed ones are refused. Anything
83
+ else is rejected: a subdirectory of a worktree, a relative or nonexistent path, and a separate
84
+ repository, including one made with `git init` elsewhere. It defaults to the launch worktree's root.
85
+ Git runs without `GIT_*` variables, so `GIT_DIR` cannot redirect the check.
86
+
87
+ ## Registering the server
88
+
89
+ The commands below run `vouchington` from the repository's own `node_modules`, so a fresh worktree
90
+ uses the version its lockfile pins. Set the blackboard credentials in the environment the harness
91
+ gives the server.
92
+
93
+ Claude Code, `.mcp.json`:
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "vouchington-tooling": {
99
+ "command": "bash",
100
+ "args": ["-c", "exec \"$(git rev-parse --show-toplevel)/node_modules/.bin/vouchington\" mcp"]
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ Codex, `.codex/config.toml`:
107
+
108
+ ```toml
109
+ [mcp_servers.vouchington-tooling]
110
+ command = "bash"
111
+ args = ["-c", "exec \"$(git rev-parse --show-toplevel)/node_modules/.bin/vouchington\" mcp"]
112
+ default_tools_approval_mode = "approve"
113
+ required = false
114
+ ```
115
+
116
+ Approving every tool of the server at once:
117
+
118
+ - Claude Code permission rule: `mcp__vouchington-tooling__*`
119
+ - Cursor permission rule: `Mcp(vouchington-tooling:*)`
120
+ - Codex: `default_tools_approval_mode = "approve"` above
121
+
122
+ ## What is verified
123
+
124
+ Covered by this package's tests: the tool list and schemas, every tool's success and rejection
125
+ paths against a faked blackboard client, the worktree gate against real temporary git repositories,
126
+ an in-process client and server round trip through the SDK's in-memory transport, and a spawned
127
+ `vouchington mcp` process driven over real stdio.
128
+
129
+ Not verified, and tracked as the unchecked Phase 0 checklist in
130
+ [#324](https://github.com/vouchington/vouchington-tooling/issues/324): each harness's approval
131
+ syntax and whether the rules above take effect, the working directory after entering a worktree,
132
+ environment interpolation and credential passing, `gh` authentication, behavior in a freshly
133
+ created worktree, and connectivity from automation. Treat the registration snippets and permission
134
+ rules as untested per harness until that checklist is complete.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.24.1",
3
+ "version": "0.26.0",
4
4
  "description": "Vouchington CLI and extractable tooling libraries.",
5
5
  "homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
6
6
  "bugs": {
@@ -352,21 +352,26 @@
352
352
  "picomatch": "4.0.7",
353
353
  "remark": "15.0.1",
354
354
  "remark-gfm": "4.0.1",
355
- "smol-toml": "1.8.0",
355
+ "smol-toml": "1.9.0",
356
356
  "spdx-expression-parse": "5.0.0",
357
357
  "yaml": "2.9.1"
358
358
  },
359
359
  "devDependencies": {
360
360
  "@ast-grep/cli": "0.45.3",
361
+ "@modelcontextprotocol/sdk": "1.31.0",
361
362
  "@types/picomatch": "^4.0.3",
362
363
  "@types/spdx-expression-parse": "4.0.0",
363
364
  "agent-blackboard": "^0.6.0"
364
365
  },
365
366
  "peerDependencies": {
367
+ "@modelcontextprotocol/sdk": "^1.31.0",
366
368
  "typescript": ">=5",
367
369
  "vitest": ">=5"
368
370
  },
369
371
  "peerDependenciesMeta": {
372
+ "@modelcontextprotocol/sdk": {
373
+ "optional": true
374
+ },
370
375
  "typescript": {
371
376
  "optional": true
372
377
  },
@@ -13,38 +13,75 @@ Use when the current repository provides a journal, blackboard, or equivalent du
13
13
  record. Read local `AGENTS.md` for the provider, credential, retention, and
14
14
  subagent-identity rules.
15
15
 
16
+ Journal operations are tools of the `vouchington-tooling` MCP server (`vouchington mcp`):
17
+ `journal_append`, `journal_entries`, `outbox_status`, `outbox_flush`, `session_ensure`,
18
+ `snapshot_export`, and `session_archive`. A harness may prefix the tool names with the server name.
19
+ Every call takes an exact `sessionId`, never inferred, whose meaning depends on the tool:
20
+
21
+ - `journal_append` and `session_ensure`: the session written or ensured, which is the caller's own
22
+ session unless a runner ensures a child identity.
23
+ - `journal_entries` and `session_archive`: the session read or archived, which during distillation
24
+ belongs to another agent.
25
+ - `snapshot_export`, `outbox_status`, and `outbox_flush`: only the caller. The outbox tools cover
26
+ every record in the worktree outbox, not only that session's.
27
+
28
+ Every call may take `worktree`, the absolute path of a worktree of the current repository (the
29
+ launch worktree by default). Writing or retrying an entry needs no provider skill, temporary file,
30
+ `--file` flag, or replay command.
31
+ If these tools are not available because the server is not registered or not connected, stop and
32
+ report that the journal server is unavailable. Do not fall back to a CLI command.
33
+
16
34
  1. Capture consequential observations before filing an issue: failed or recovered checks, denied or
17
35
  approved permissions, repeated fixes, scope changes, first-party tool behavior, and architectural
18
36
  findings. Record useful resolved outcomes as well as unresolved gaps. Include bounded evidence,
19
37
  affected areas, an explicit disposition, and an existing tracking reference when present.
20
38
  Journal meaningful skips or bypasses of applicable configured workflows before completion, with
21
39
  the owning workflow or command-catalog entrypoint, reason, and observed result/action.
22
- 2. Use the shared validated envelope with storage `type: journal` or `retrospective`, canonical exact
23
- entry repositories, stable `sourceEventId`, work outcome, and explicit feedback coverage. Category
24
- is optional context; it never changes storage type or distillation eligibility. Generate routine
25
- facts and metadata through the approved composer instead of hand-authoring factual markers.
40
+ 2. Record each observation with one `journal_append` call and pass the note as its `markdown`
41
+ argument (at most 12000 bytes). Required arguments are `sessionId`, `parentSessionId` (null for a
42
+ root session), `agent`, `version`, `mode`, `markdown`, a stable `sourceEventId`, `workOutcome`,
43
+ canonical exact `repositories`, and explicit `feedbackCoverage`. Also pass an ISO 8601
44
+ `timestamp` fixed before the first attempt: the server otherwise generates one, and a failed or
45
+ timed-out call returns no result to learn it from. Nothing is written unless the
46
+ whole envelope validates. The tool writes journal entries; `category` is optional context and
47
+ never changes storage type or distillation eligibility. Generate routine facts and metadata
48
+ through the approved composer and pass its output as `markdown` instead of hand-authoring
49
+ factual markers. `journal_append` stores only journal entries: save a composed retrospective
50
+ through the retrospective skill's writer, never through `journal_append`.
26
51
  3. Preserve exact provider session and parent identities. Each agent writes only its own session.
27
- Update that session's cumulative repository union before appending; never infer another repository
28
- from prose or create a child identity from a model guess.
29
- 4. Select the repository's trusted mode explicitly. Interactive outages may retain validated,
30
- sanitized feedback in the bounded durable outbox. Report pending count and delivery state, replay
31
- with the same source identity, and continue primary work only after persistence succeeds. A full,
32
- unsafe, or unwritable outbox blocks capture; never evict or silently discard an unsent record.
33
- 5. Autonomous runners require online session ensure, a fresh admission write, and readback before
34
- launching an attempt. Terminal reporting preserves work outcome separately from feedback
35
- coverage and delivery. A filesystem outbox never grants admission or acknowledged completion.
36
- 6. Use at-least-once delivery with consumer deduplication by exact session/source identity. A
37
- transport timeout can leave a late durable write; pending or blocked is never an acknowledged
38
- receipt. Replay verifies matching content before retrying and rejects conflicting source reuse.
39
- 7. Read journal entries oldest-first for retrospectives. Record explicit none-observed with inspected
40
- scope, or not-assessed/unavailable with reason, when evidence does not establish a finding. A
41
- permission request is not proof of approval or denial; localhost refusal is not proof of sandbox
42
- enforcement. Mark partial capture and dropped counts instead of reporting clean evidence.
52
+ `journal_append` ensures that session and merges the entry's `repositories` into the session's
53
+ cumulative repository union, so list every repository the entry concerns. Never infer another
54
+ repository from prose or create a child identity from a model guess. Call `session_ensure` with
55
+ the exact identity only when a runner must confirm the session before work starts.
56
+ 4. Select the repository's trusted `mode` (`interactive` or `autonomous`) explicitly. In interactive
57
+ mode an outage may retain the validated, sanitized record in the bounded durable outbox, and
58
+ `journal_append` reports it as pending. Report the pending count from `outbox_status`, deliver
59
+ with `outbox_flush` once the provider is reachable, and continue primary work only after
60
+ persistence succeeds. A full, unsafe, or unwritable outbox blocks capture; never evict or
61
+ silently discard an unsent record.
62
+ 5. Autonomous runners require online `session_ensure`, a fresh admission `journal_append`, and
63
+ readback before launching an attempt. Give each attempt's admission entry a `sourceEventId`
64
+ unique to that attempt: reusing an earlier one returns the earlier receipt, which does not
65
+ prove a fresh write. Autonomous mode has no filesystem outbox, so a failed delivery is an error.
66
+ Terminal reporting preserves work outcome separately from feedback coverage and delivery. A
67
+ filesystem outbox never grants admission or acknowledged completion.
68
+ 6. Use at-least-once delivery with consumer deduplication by exact session/source identity. To
69
+ retry a pending or failed append, call `journal_append` again with the same `sourceEventId`,
70
+ content, and `timestamp` from the first attempt: the whole envelope must match, and conflicting
71
+ source reuse is rejected. A transport timeout can leave a late
72
+ durable write; pending or blocked is never an acknowledged receipt.
73
+ 7. Read the session's entries oldest-first with `journal_entries` for retrospectives. It returns
74
+ every entry with its envelope, including its type and repository tags, so a retrospective can
75
+ find an existing retrospective and keep entry-level tags. Record explicit
76
+ none-observed with inspected scope, or not-assessed/unavailable with reason, when evidence does
77
+ not establish a finding. A permission request is not proof of approval or denial; localhost
78
+ refusal is not proof of sandbox enforcement. Mark partial capture and dropped counts instead of
79
+ reporting clean evidence.
43
80
 
44
81
  Never search for, print, invent, or mint credentials. Durable entries and outbox records contain only
45
82
  bounded structured facts or sanitized summaries, never raw command output, transcript content,
46
83
  environment dumps, provider payloads, or secrets. Known-secret redaction supplements the author's
47
84
  minimization responsibility; it cannot prove arbitrary prose contains no undisclosed secret.
48
85
 
49
- Consumer wrappers own service configuration, trusted mode selection, commands, outbox location,
50
- issue routing, and archival authorization.
86
+ Consumer wrappers own service configuration, server registration and approval rules, trusted mode
87
+ selection, issue routing, and archival authorization. The server fixes the outbox location.
@@ -4,7 +4,7 @@
4
4
  {
5
5
  "name": "agent-workflow",
6
6
  "plugin": "vouchington-workflow",
7
- "pluginVersion": "0.9.0",
7
+ "pluginVersion": "0.10.0",
8
8
  "path": "agent-workflow/SKILL.md",
9
9
  "prerequisites": ["github-issue", "pr-description", "review-ci-logs"]
10
10
  },
@@ -18,13 +18,13 @@
18
18
  {
19
19
  "name": "blackboard",
20
20
  "plugin": "vouchington-workflow",
21
- "pluginVersion": "0.9.0",
21
+ "pluginVersion": "0.10.0",
22
22
  "path": "blackboard/SKILL.md"
23
23
  },
24
24
  {
25
25
  "name": "dependabot",
26
26
  "plugin": "vouchington-workflow",
27
- "pluginVersion": "0.9.0",
27
+ "pluginVersion": "0.10.0",
28
28
  "path": "dependabot/SKILL.md",
29
29
  "prerequisites": ["github-actions-checklist"]
30
30
  },
@@ -38,26 +38,26 @@
38
38
  {
39
39
  "name": "git-commit-checklist",
40
40
  "plugin": "vouchington-workflow",
41
- "pluginVersion": "0.9.0",
41
+ "pluginVersion": "0.10.0",
42
42
  "path": "git-commit-checklist/SKILL.md"
43
43
  },
44
44
  {
45
45
  "name": "github-actions-authoring",
46
46
  "plugin": "vouchington-workflow",
47
- "pluginVersion": "0.9.0",
47
+ "pluginVersion": "0.10.0",
48
48
  "path": "github-actions-authoring/SKILL.md",
49
49
  "prerequisites": ["github-actions-checklist"]
50
50
  },
51
51
  {
52
52
  "name": "github-actions-checklist",
53
53
  "plugin": "vouchington-workflow",
54
- "pluginVersion": "0.9.0",
54
+ "pluginVersion": "0.10.0",
55
55
  "path": "github-actions-checklist/SKILL.md"
56
56
  },
57
57
  {
58
58
  "name": "github-issue",
59
59
  "plugin": "vouchington-workflow",
60
- "pluginVersion": "0.9.0",
60
+ "pluginVersion": "0.10.0",
61
61
  "path": "github-issue/SKILL.md"
62
62
  },
63
63
  {
@@ -70,26 +70,26 @@
70
70
  {
71
71
  "name": "npm-publishing",
72
72
  "plugin": "vouchington-workflow",
73
- "pluginVersion": "0.9.0",
73
+ "pluginVersion": "0.10.0",
74
74
  "path": "npm-publishing/SKILL.md"
75
75
  },
76
76
  {
77
77
  "name": "organize-github-issues",
78
78
  "plugin": "vouchington-workflow",
79
- "pluginVersion": "0.9.0",
79
+ "pluginVersion": "0.10.0",
80
80
  "path": "organize-github-issues/SKILL.md",
81
81
  "prerequisites": ["github-issue"]
82
82
  },
83
83
  {
84
84
  "name": "package-json-checklist",
85
85
  "plugin": "vouchington-workflow",
86
- "pluginVersion": "0.9.0",
86
+ "pluginVersion": "0.10.0",
87
87
  "path": "package-json-checklist/SKILL.md"
88
88
  },
89
89
  {
90
90
  "name": "planning",
91
91
  "plugin": "vouchington-workflow",
92
- "pluginVersion": "0.9.0",
92
+ "pluginVersion": "0.10.0",
93
93
  "path": "planning/SKILL.md",
94
94
  "prerequisites": ["github-issue"]
95
95
  },
@@ -115,53 +115,53 @@
115
115
  {
116
116
  "name": "pr-description",
117
117
  "plugin": "vouchington-workflow",
118
- "pluginVersion": "0.9.0",
118
+ "pluginVersion": "0.10.0",
119
119
  "path": "pr-description/SKILL.md"
120
120
  },
121
121
  {
122
122
  "name": "retrospective",
123
123
  "plugin": "vouchington-workflow",
124
- "pluginVersion": "0.9.0",
124
+ "pluginVersion": "0.10.0",
125
125
  "path": "retrospective/SKILL.md"
126
126
  },
127
127
  {
128
128
  "name": "retrospective-distill",
129
129
  "plugin": "vouchington-workflow",
130
- "pluginVersion": "0.9.0",
130
+ "pluginVersion": "0.10.0",
131
131
  "path": "retrospective-distill/SKILL.md",
132
132
  "prerequisites": ["github-issue"]
133
133
  },
134
134
  {
135
135
  "name": "review-ci-logs",
136
136
  "plugin": "vouchington-workflow",
137
- "pluginVersion": "0.9.0",
137
+ "pluginVersion": "0.10.0",
138
138
  "path": "review-ci-logs/SKILL.md",
139
139
  "prerequisites": ["github-actions-checklist", "pr-description"]
140
140
  },
141
141
  {
142
142
  "name": "review-github-issue-taxonomy",
143
143
  "plugin": "vouchington-workflow",
144
- "pluginVersion": "0.9.0",
144
+ "pluginVersion": "0.10.0",
145
145
  "path": "review-github-issue-taxonomy/SKILL.md",
146
146
  "prerequisites": ["github-issue"]
147
147
  },
148
148
  {
149
149
  "name": "revisit-followups",
150
150
  "plugin": "vouchington-workflow",
151
- "pluginVersion": "0.9.0",
151
+ "pluginVersion": "0.10.0",
152
152
  "path": "revisit-followups/SKILL.md",
153
153
  "prerequisites": ["github-issue"]
154
154
  },
155
155
  {
156
156
  "name": "stacked-prs",
157
157
  "plugin": "vouchington-workflow",
158
- "pluginVersion": "0.9.0",
158
+ "pluginVersion": "0.10.0",
159
159
  "path": "stacked-prs/SKILL.md"
160
160
  },
161
161
  {
162
162
  "name": "static-analysis-checklist",
163
163
  "plugin": "vouchington-workflow",
164
- "pluginVersion": "0.9.0",
164
+ "pluginVersion": "0.10.0",
165
165
  "path": "static-analysis-checklist/SKILL.md",
166
166
  "prerequisites": ["github-actions-checklist"]
167
167
  },
@@ -12,26 +12,48 @@ Local policy overrides these defaults; do not reload an already-read adapter or
12
12
  Use when completed retrospectives or journals should become durable follow-up work. Read local
13
13
  `AGENTS.md`, issue policy, and journal retention rules before any mutation.
14
14
 
15
- 1. Enumerate only completed, eligible session records. For repository-scoped work, filter sessions
16
- by repository membership and use only entries attributed to that repository. Leave untagged
17
- legacy records unclassified. Do not infer their repository. Leave in-progress sessions intact.
18
- 2. Validate storage type and the shared envelope independently of optional category. Never repair
15
+ 1. Enumerate only completed, eligible session records with the `snapshot_export` tool of the
16
+ `vouchington-tooling` MCP server, narrowing by `agent`, `version`, `parentSessionId`, exact
17
+ `data` fields, `dataArrayContains`, and `inactiveForHours`. It exports non-archived sessions to a
18
+ private local file and returns the path, counts, checksum, and manifest, never the records.
19
+ Before exporting, call `outbox_flush` and then `outbox_status` for every worktree that
20
+ `git worktree list` reports, passing each path as `worktree`, and stop if any still reports
21
+ pending records: an archived session refuses later delivery, so a retained record would never
22
+ be distilled. Outboxes in removed worktrees or on other machines cannot be drained this way, so
23
+ select with `inactiveForHours` to give them time to deliver. Leave in-progress sessions intact.
24
+ If the server is not connected, stop and report it; do not fall back to a CLI command.
25
+ 2. Before using any record, verify the file against the returned checksum, counts, and terminal
26
+ manifest with the consumer's approved snapshot reader, and stop on a mismatch rather than
27
+ treating missing records as absent. Read full records, with their storage type, repository
28
+ tags, source identity, coverage, and outcomes, from that file. Do not distill from
29
+ `journal_entries`: it reads one session at a time and has no checksum or manifest to show that
30
+ the read is complete. For repository-scoped work, filter sessions by
31
+ repository membership (`dataArrayContains` with `repositories` and the exact `owner/name`) and
32
+ use only entries attributed to that repository. Leave untagged legacy records unclassified. Do
33
+ not infer their repository.
34
+ 3. Validate storage type and the shared envelope independently of optional category. Never repair
19
35
  unknown legacy types or repository provenance by inference. Quarantine malformed sessions with
20
36
  an explicit reason while processing valid unrelated sessions. Deduplicate at-least-once records
21
37
  by exact session/source identity and reject conflicting duplicate content. Retain coverage,
22
38
  dropped counts, requested versus observed outcomes, and useful resolved findings.
23
- 3. Cluster findings by root cause. Prefer a few broad actionable themes over many narrow issues.
39
+ 4. Cluster findings by root cause. Prefer a few broad actionable themes over many narrow issues.
24
40
  Treat a finding already linked to an open tracker as context, not a duplicate.
25
- 4. Verify each candidate against the current base. Search existing issues and open changes before
41
+ 5. Verify each candidate against the current base. Search existing issues and open changes before
26
42
  drafting. Skip work that is complete, explicitly rejected, or already covered. A first-party version
27
43
  bump is not proof of resolution: verify the adopted change against the original finding before
28
44
  deferring. Capture a new observation in the journal before filing it.
29
- 5. Draft self-contained issues with the problem, concrete proposed work, relevant areas, and
45
+ 6. Draft self-contained issues with the problem, concrete proposed work, relevant areas, and
30
46
  validation. Route every authorized creation through
31
47
  [github-issue](../github-issue/SKILL.md), including its repository gate, label approval, and
32
48
  denied-external tracking behavior.
33
- 6. Archive only records fully processed across every represented repository, under the repository's
34
- retention rules. A one-repository pass leaves a multi-repository session active until the other
49
+ 7. Archive only verified records fully processed across every represented repository, and never
50
+ while any worktree's `outbox_status` reports pending records, under the repository's retention
51
+ rules. Make one `session_archive` call per session, whose `sessionId` is the archived session,
52
+ not the caller. Immediately before each call, read that session with `journal_entries` and
53
+ archive only if its entries match the verified snapshot's by source identity; otherwise leave it
54
+ for the next pass, because an entry added after the export would never be distilled.
55
+ Archiving makes the session's metadata immutable, so it needs the archival authorization that
56
+ local policy requires. A one-repository pass leaves a multi-repository session active until the other
35
57
  repositories are reviewed. Report reviewed, fixed, duplicate, deferred, quarantined, and
36
58
  actionable dispositions with reasons. Keep the top five themes in human prose without dropping
37
59
  underlying findings or unresolved records.
@@ -40,8 +62,10 @@ Use source records only for local verification and leave them in the repository'
40
62
  or retention system. Public issue bodies contain only the minimum bounded facts or redacted
41
63
  summaries needed to establish the problem, proposed work, relevant areas, and validation. Never
42
64
  embed unredacted logs, command output, environment details, provider payloads, or transcript
43
- content.
65
+ content. A snapshot file is a private local copy of source records: never commit or attach it, or
66
+ copy its contents into an issue.
44
67
 
45
- This skill supplies no journal API, issue repository, labels, milestones, projects, archival
46
- command, or approval model. Consumer wrappers cannot weaken this export boundary; they provide only
47
- those local details.
68
+ This skill supplies no issue repository, labels, milestones, projects, or approval model; it reads
69
+ sessions only from the snapshot file that `snapshot_export` writes, and archives them only with
70
+ `session_archive`. Consumer wrappers cannot weaken this export
71
+ boundary; they provide only those local details.