@polygraph/codex-plugin 0.4.41 → 0.4.43
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.
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +1 -0
- package/agents/polygraph-delegate-subagent.toml +9 -5
- package/hooks/record-session-mapping.mjs +61 -8
- package/hooks/reinject-polygraph-context.mjs +40 -11
- package/package.json +1 -1
- package/skills/adversarial-review/SKILL.md +15 -0
- package/skills/await-polygraph-ci/SKILL.md +1 -1
- package/skills/polygraph/SKILL.md +33 -202
- package/skills/polygraph/reference/publish-changes.md +151 -0
- package/skills/session-debrief/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ It detects your AI agent — Claude Code, Codex, OpenCode, and more — and inst
|
|
|
38
38
|
## Skills
|
|
39
39
|
|
|
40
40
|
- **polygraph** — Comprehensive guidance for Polygraph sessions: shared context, repository graph visibility, PR/CI state, delegation, and session management
|
|
41
|
+
- **adversarial-review** — Second-opinion review of a session's work by independent reviewer agents, one per repo, running under a read-only `reviewer` role
|
|
41
42
|
- **await-polygraph-ci** — Wait for CI pipelines to settle across all repos in a session, investigate failures, and present fix options
|
|
42
43
|
- **get-latest-ci** — One-shot fetch of the latest CI pipeline execution for the current branch
|
|
43
44
|
- **session-debrief** — Analyze the raw logs of past Polygraph sessions and produce structured, rank-ordered debriefs for use in a different session
|
|
@@ -16,13 +16,14 @@ The main agent provides these parameters in the prompt:
|
|
|
16
16
|
| `sessionId` | The Polygraph session ID |
|
|
17
17
|
| `repo` | Repository to delegate to (e.g., `org/repo-name`) |
|
|
18
18
|
| `instruction` | The task instruction for the child agent |
|
|
19
|
+
| `role` | (Optional) Agent slot within the repo; omit for the default role. Pass the SAME role on every `spawn_agent`/`show_agent`/`stop_agent` call for this delegation. |
|
|
19
20
|
| `context` | (Optional) Additional context to pass to the child agent |
|
|
20
21
|
|
|
21
22
|
## Delegating work
|
|
22
23
|
|
|
23
|
-
Call the `spawn_agent` tool to start a child agent on the repo or to send a follow-up to an active task. Follow-up routing is automatic: if
|
|
24
|
+
Call the `spawn_agent` tool to start a child agent on the repo or to send a follow-up to an active task. Follow-up routing is automatic per (repo, role): if that (repo, role) already has an active child task (working or paused on input), the orchestrator delivers your `instruction` to that task as a follow-up message rather than starting a second run; otherwise it starts a new child run. A repo therefore has at most one active child per role, though agents with different roles can run in the same repo concurrently.
|
|
24
25
|
|
|
25
|
-
`repo` must be a repository other than the one the parent agent is working in — never delegate into the parent's own repo.
|
|
26
|
+
`repo` must be a repository other than the one the parent agent is working in — never delegate into the parent's own repo.
|
|
26
27
|
|
|
27
28
|
**Resume/reconstruction is read-only.** If the parent asks you to resume, reconnect, restore, or reconstruct a preserved session without an explicit new change request from the user, do not call `spawn_agent` to continue work. Use `show_agent` only as needed to read status/log context, return a concise restoration summary, and stop. After resuming, wait for explicit user instructions before any child agent makes changes.
|
|
28
29
|
|
|
@@ -31,6 +32,7 @@ spawn_agent(
|
|
|
31
32
|
sessionId: "<sessionId>",
|
|
32
33
|
repo: "<repo>",
|
|
33
34
|
instruction: "<instruction>",
|
|
35
|
+
role: "<role, if any>",
|
|
34
36
|
context: "<context>"
|
|
35
37
|
)
|
|
36
38
|
```
|
|
@@ -45,6 +47,7 @@ Call `show_agent` in a loop, passing `waitForTransitionMs: 50000` on every call:
|
|
|
45
47
|
show_agent(
|
|
46
48
|
sessionId: "<sessionId>",
|
|
47
49
|
repo: "<repo>",
|
|
50
|
+
role: "<role, if any>",
|
|
48
51
|
waitForTransitionMs: 50000
|
|
49
52
|
)
|
|
50
53
|
```
|
|
@@ -61,7 +64,7 @@ After calling `spawn_agent`, parse the structured JSON response:
|
|
|
61
64
|
|
|
62
65
|
Then poll `show_agent` in a loop with `waitForTransitionMs: 50000`. **Do not pass a `tail` argument** — the tool's default is sized for status polling. Only set `tail` if you have a specific reason (e.g., the default truncated output you actually need to inspect, or you are hunting for an earlier failure that scrolled off). Never ratchet `tail` upward across polls; that is what causes the polling loop to flood your context window.
|
|
63
66
|
|
|
64
|
-
The response's `children[]` array has
|
|
67
|
+
The response's `children[]` array has one entry per agent matching your query. Find YOUR delegation's entry (match on `role`; absent means the default role) and inspect:
|
|
65
68
|
|
|
66
69
|
- `child.status` — an AcpRunStatus value: one of `'created'`, `'in-progress'`, `'input-required'`, `'permission-required'`, `'completed'`, `'failed'`, `'cancelled'` (British double-L on `'cancelled'`). Note `'permission-required'` and `'input-required'` are DIFFERENT states handled by different cases below — do not conflate them.
|
|
67
70
|
- `child.inputRequiredQuestion` — populated only when `child.status === 'input-required'`; contains the verbatim question the child agent has asked the parent.
|
|
@@ -75,7 +78,7 @@ State machine:
|
|
|
75
78
|
- Read `child.inputRequiredQuestion`.
|
|
76
79
|
- Surface this question verbatim to the parent/user: "The child agent in `{child.repoFullName}` needs input: {child.inputRequiredQuestion}".
|
|
77
80
|
- Wait for the parent/user to supply an answer.
|
|
78
|
-
- Call `spawn_agent` again with the same `repo` and `instruction: <the answer>` — the orchestrator routes it to
|
|
81
|
+
- Call `spawn_agent` again with the same `repo`, the same `role`, and `instruction: <the answer>` — the orchestrator routes it to that (repo, role)'s active task automatically.
|
|
79
82
|
- Resume polling.
|
|
80
83
|
|
|
81
84
|
<!-- Claude and Codex parents handle permission gates via the native MCP elicitation dialog
|
|
@@ -96,7 +99,7 @@ State machine:
|
|
|
96
99
|
|
|
97
100
|
## Cancelling a running child
|
|
98
101
|
|
|
99
|
-
To cancel a running child mid-work, call `stop_agent` with the repo. Response:
|
|
102
|
+
To cancel a running child mid-work, call `stop_agent` with the repo (and `role`, per the parameter rule above). Response:
|
|
100
103
|
|
|
101
104
|
```json
|
|
102
105
|
{
|
|
@@ -118,6 +121,7 @@ When the child agent reaches a terminal status, return a structured summary:
|
|
|
118
121
|
## Polygraph Delegation Result
|
|
119
122
|
|
|
120
123
|
**Repo:** <repo>
|
|
124
|
+
**Role:** <role, or "default" when none was given>
|
|
121
125
|
**Status:** <success | failed | cancelled>
|
|
122
126
|
**Session ID:** <sessionId>
|
|
123
127
|
|
|
@@ -5,15 +5,27 @@
|
|
|
5
5
|
// same script ships in both plugin artifacts.
|
|
6
6
|
//
|
|
7
7
|
// File contract (must match the Polygraph CLI reader exactly):
|
|
8
|
+
// <sessionsRoot>/<POLYGRAPH_SESSION_ID>/sidecars/mapping-<agentType>-<agentSessionId>.json
|
|
9
|
+
// where sessionsRoot = $POLYGRAPH_ROOT, else `globalRoot` from
|
|
10
|
+
// ~/.polygraph/config.json, else ~/.polygraph/sessions
|
|
11
|
+
// Legacy fallback, used ONLY when <sessionsRoot>/<POLYGRAPH_SESSION_ID>
|
|
12
|
+
// does not exist (for real sessions nothing new is written here):
|
|
8
13
|
// ~/.polygraph/sidecars/<POLYGRAPH_SESSION_ID>/mapping-<agentType>-<agentSessionId>.json
|
|
9
14
|
//
|
|
15
|
+
// The session folder is a trustworthy location for this parent-transcript
|
|
16
|
+
// binding because the Polygraph CLI's child-agent sandboxes exclude the
|
|
17
|
+
// session root — children cannot write there. The CLI reads mappings from
|
|
18
|
+
// the session folder first, with the flat dir as a read-only fallback.
|
|
19
|
+
//
|
|
10
20
|
// Behaviour:
|
|
11
21
|
// - Silent no-op when POLYGRAPH_SESSION_ID is unset.
|
|
12
22
|
// - Silent no-op when POLYGRAPH_CHILD_AGENT is set (child agents must not
|
|
13
23
|
// register themselves as parents).
|
|
14
24
|
// - Atomic write: write to <path>.tmp-<pid>, then rename over final path.
|
|
15
|
-
// - Refresh: when a valid prior mapping for the same session already exists
|
|
16
|
-
//
|
|
25
|
+
// - Refresh: when a valid prior mapping for the same session already exists
|
|
26
|
+
// (checked in the new location first, then the legacy flat dir), preserve
|
|
27
|
+
// its firstSeenAt and only update lastSeenAt + mutable fields — so
|
|
28
|
+
// migrating a mapping from the legacy dir keeps firstSeenAt continuity.
|
|
17
29
|
// - All failures are silently swallowed; never writes to stdout (Claude Code
|
|
18
30
|
// injects hook stdout into the model context); never exits non-zero.
|
|
19
31
|
|
|
@@ -90,9 +102,35 @@ function sanitizeFilename(str) {
|
|
|
90
102
|
return str.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
// Resolve the root directory that holds per-session folders:
|
|
106
|
+
// $POLYGRAPH_ROOT, else `globalRoot` from ~/.polygraph/config.json, else
|
|
107
|
+
// ~/.polygraph/sessions. Must match the Polygraph CLI's own resolution.
|
|
108
|
+
export function sessionsRoot(home = process.env.HOME?.trim() || homedir()) {
|
|
109
|
+
const fromEnv = process.env.POLYGRAPH_ROOT?.trim();
|
|
110
|
+
if (fromEnv) return fromEnv;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const config = tryParseJson(
|
|
114
|
+
readFileSync(join(home, '.polygraph', 'config.json'), 'utf8')
|
|
115
|
+
);
|
|
116
|
+
if (typeof config?.globalRoot === 'string' && config.globalRoot.trim()) {
|
|
117
|
+
return config.globalRoot.trim();
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// no config — use the default
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return join(home, '.polygraph', 'sessions');
|
|
124
|
+
}
|
|
125
|
+
|
|
93
126
|
/**
|
|
94
127
|
* Write (or refresh) the agent-capture mapping file.
|
|
95
128
|
*
|
|
129
|
+
* Written into the session folder (`<sessionsRoot>/<sessionId>/sidecars/`)
|
|
130
|
+
* when the session directory exists; only when it does not exist does the
|
|
131
|
+
* write fall back to the legacy flat `~/.polygraph/sidecars/<sessionId>/`
|
|
132
|
+
* dir — for real sessions nothing new lands under the flat dir.
|
|
133
|
+
*
|
|
96
134
|
* @param {object} opts
|
|
97
135
|
* @param {string} opts.agentType 'claude' | 'codex'
|
|
98
136
|
* @param {string} opts.agentSessionId The harness's own session id.
|
|
@@ -106,19 +144,33 @@ export function writeCaptureMapping(
|
|
|
106
144
|
{ agentType, agentSessionId, polygraphSessionId, cwd, transcriptPath, pid },
|
|
107
145
|
home = process.env.HOME?.trim() || homedir()
|
|
108
146
|
) {
|
|
109
|
-
const sidecarDir = join(home, '.polygraph', 'sidecars', polygraphSessionId);
|
|
110
|
-
mkdirSync(sidecarDir, { recursive: true });
|
|
111
|
-
|
|
112
147
|
const filenamePart = sanitizeFilename(`${agentType}-${agentSessionId}`);
|
|
113
|
-
const
|
|
148
|
+
const fileName = `mapping-${filenamePart}.json`;
|
|
149
|
+
|
|
150
|
+
const sessionDir = join(sessionsRoot(home), polygraphSessionId);
|
|
151
|
+
const sessionSidecarDir = join(sessionDir, 'sidecars');
|
|
152
|
+
const legacyDir = join(home, '.polygraph', 'sidecars', polygraphSessionId);
|
|
153
|
+
|
|
154
|
+
// New location when the session directory exists; legacy flat dir only
|
|
155
|
+
// when it does not.
|
|
156
|
+
const targetDir = existsSync(sessionDir) ? sessionSidecarDir : legacyDir;
|
|
157
|
+
mkdirSync(targetDir, { recursive: true });
|
|
158
|
+
|
|
159
|
+
const finalPath = join(targetDir, fileName);
|
|
114
160
|
const tmpPath = `${finalPath}.tmp-${process.pid}`;
|
|
115
161
|
|
|
116
162
|
const now = Date.now();
|
|
117
163
|
|
|
118
164
|
// Refresh semantics: preserve firstSeenAt from a valid prior mapping.
|
|
165
|
+
// Check the new location first, then the legacy flat dir — this keeps
|
|
166
|
+
// firstSeenAt continuity when migrating a mapping from the legacy dir.
|
|
119
167
|
let firstSeenAt = now;
|
|
120
|
-
|
|
121
|
-
|
|
168
|
+
for (const candidate of [
|
|
169
|
+
join(sessionSidecarDir, fileName),
|
|
170
|
+
join(legacyDir, fileName),
|
|
171
|
+
]) {
|
|
172
|
+
if (!existsSync(candidate)) continue;
|
|
173
|
+
const existing = tryParseJson(readFileSync(candidate, 'utf8'));
|
|
122
174
|
if (
|
|
123
175
|
existing !== null &&
|
|
124
176
|
existing.version === 1 &&
|
|
@@ -127,6 +179,7 @@ export function writeCaptureMapping(
|
|
|
127
179
|
Number.isFinite(existing.firstSeenAt)
|
|
128
180
|
) {
|
|
129
181
|
firstSeenAt = existing.firstSeenAt;
|
|
182
|
+
break;
|
|
130
183
|
}
|
|
131
184
|
}
|
|
132
185
|
|
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
// into the model.
|
|
9
9
|
//
|
|
10
10
|
// Everything is read from local Polygraph state — no network calls:
|
|
11
|
+
// <sessionsRoot>/<polygraphSessionId>/sidecars/parent-<agentSessionId>.json
|
|
12
|
+
// (sessionsRoot = $POLYGRAPH_ROOT or ~/.polygraph/sessions) maps this
|
|
13
|
+
// agent session id -> Polygraph session id (the "parent log sidecar"
|
|
14
|
+
// the CLI uses to stream parent-agent activity to the UI). Falls back
|
|
15
|
+
// to the legacy location for sessions created by older CLIs:
|
|
11
16
|
// ~/.polygraph/sidecars/<polygraphSessionId>/parent-<agentSessionId>.json
|
|
12
|
-
// maps this agent session id -> Polygraph session id (the "parent log
|
|
13
|
-
// sidecar" the CLI uses to stream parent-agent activity to the UI).
|
|
14
17
|
// ~/.polygraph/sessions/<polygraphSessionId>/session/session.json
|
|
15
18
|
// holds the session's repos, agentType, and orgId.
|
|
16
19
|
// ~/.polygraph/config.json
|
|
@@ -83,25 +86,28 @@ function readJson(file) {
|
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
// Resolve the root directory that holds per-session folders. Overridable via
|
|
90
|
+
// POLYGRAPH_ROOT (must match the Polygraph CLI's own resolution).
|
|
91
|
+
function sessionsRoot(root) {
|
|
92
|
+
return process.env.POLYGRAPH_ROOT?.trim() || path.join(root, 'sessions');
|
|
93
|
+
}
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
// Scan the immediate subdirectories of `baseDir`; for each, `candidatePath`
|
|
96
|
+
// maps the subdirectory name to a candidate sidecar file. Returns the first
|
|
97
|
+
// parsed match, or null.
|
|
98
|
+
function scanForSidecar(baseDir, candidatePath) {
|
|
99
|
+
if (!existsSync(baseDir)) return null;
|
|
93
100
|
|
|
94
|
-
const fileName = `parent-${agentSessionId}.json`;
|
|
95
101
|
let entries;
|
|
96
102
|
try {
|
|
97
|
-
entries = readdirSync(
|
|
103
|
+
entries = readdirSync(baseDir, { withFileTypes: true });
|
|
98
104
|
} catch {
|
|
99
105
|
return null;
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
for (const entry of entries) {
|
|
103
109
|
if (!entry.isDirectory()) continue;
|
|
104
|
-
const candidate =
|
|
110
|
+
const candidate = candidatePath(entry.name);
|
|
105
111
|
if (existsSync(candidate)) {
|
|
106
112
|
return readJson(candidate);
|
|
107
113
|
}
|
|
@@ -109,6 +115,29 @@ export function findSidecar(agentSessionId, root = polygraphRoot()) {
|
|
|
109
115
|
return null;
|
|
110
116
|
}
|
|
111
117
|
|
|
118
|
+
// Find the sidecar that maps an agent session id to a Polygraph session.
|
|
119
|
+
// Checks the new per-session layout first, then falls back to the legacy
|
|
120
|
+
// shared sidecars directory. Returns the parsed sidecar object, or null when
|
|
121
|
+
// none matches.
|
|
122
|
+
export function findSidecar(agentSessionId, root = polygraphRoot()) {
|
|
123
|
+
if (!agentSessionId) return null;
|
|
124
|
+
|
|
125
|
+
const fileName = `parent-${agentSessionId}.json`;
|
|
126
|
+
|
|
127
|
+
// New layout: <sessionsRoot>/<sessionId>/sidecars/parent-<agentSessionId>.json
|
|
128
|
+
const sessionsDir = sessionsRoot(root);
|
|
129
|
+
const fromSessions = scanForSidecar(sessionsDir, (sessionId) =>
|
|
130
|
+
path.join(sessionsDir, sessionId, 'sidecars', fileName)
|
|
131
|
+
);
|
|
132
|
+
if (fromSessions) return fromSessions;
|
|
133
|
+
|
|
134
|
+
// Legacy layout: <root>/sidecars/<sessionId>/parent-<agentSessionId>.json
|
|
135
|
+
const legacyDir = path.join(root, 'sidecars');
|
|
136
|
+
return scanForSidecar(legacyDir, (sessionId) =>
|
|
137
|
+
path.join(legacyDir, sessionId, fileName)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
112
141
|
// Build the context block for a Polygraph session, or null when the agent is
|
|
113
142
|
// not running inside a Polygraph session.
|
|
114
143
|
export function buildPolygraphContext(agentSessionId, root = polygraphRoot()) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adversarial-review
|
|
3
|
+
description: Independent second-opinion review of a Polygraph session's work. USE WHEN user says "adversarial review", "review this session", or when the Polygraph CLI launches an agent with an instruction to load this skill.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Adversarial Review
|
|
8
|
+
|
|
9
|
+
1. **Pick the agent.** Ask whether Claude, Codex, or OpenCode should review — `claude`, `codex`, or `opencode` for `spawn_agent`'s `agent` parameter. Skip if the user already named one.
|
|
10
|
+
2. **Get the session description.**
|
|
11
|
+
3. **Get each repo's plan.** Ask each repo's agent to provide the plan.
|
|
12
|
+
4. **Delegate one reviewer per repo** in parallel, with `role: "reviewer"`. Pass the overall plan and that repo's plan, and ask it to review the code, identify issues, and return a summary. Do the delegation even for the "initiator" repo.
|
|
13
|
+
5. **Summarize.** Once every review is back, analyze them and present one summary to the user.
|
|
14
|
+
6. **Ask what next.** Address the feedback, upload the summary via `upload_artifact`, or continue with the session. Skip if the user already said.
|
|
15
|
+
7. If the user selects "address the feedback", pass each repo's feedback to the repo default agent (not the reviewer). The initiator should fix things itself without delegating.
|
|
@@ -165,7 +165,7 @@ For each repo with `ciStatus: FAILED`, branch on the PR's `ci` object from `show
|
|
|
165
165
|
show_agent(sessionId: "<session-id>", repo: "frontend")
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
Poll until the child agent's status indicates completion. Use the `tail` parameter to retrieve recent output lines containing the investigation results.
|
|
168
|
+
Poll until the child agent's status indicates completion (pass the same `role` you spawned with, if any). Use the `tail` parameter to retrieve recent output lines containing the investigation results.
|
|
169
169
|
|
|
170
170
|
4. Collect each child agent's response from the status output. If a child agent fails or gets stuck, use `stop_agent` to terminate it and skip that repo.
|
|
171
171
|
|
|
@@ -55,9 +55,9 @@ Polygraph functionality is available via both MCP tools and CLI commands. Use wh
|
|
|
55
55
|
| --- | --- | --- |
|
|
56
56
|
| `list_repos` | `polygraph repo list` | Discover candidate repositories. Candidate entries do not include repository descriptions; use `semanticQuery` for natural-language discovery. |
|
|
57
57
|
| `start_session` | `polygraph session start --repo <ids>` | Initialize a Polygraph session with selected repositories |
|
|
58
|
-
| `spawn_agent` | — | Start a new child task or send a follow-up to an active task in another repository. Input: `{ sessionId, repo, instruction, context? }`. Output: `{ taskId, message, status: 'delegated' }`. Follow-up routing is automatic: if
|
|
59
|
-
| `show_agent` | — | Poll
|
|
60
|
-
| `stop_agent` | — | Cancel an in-progress child. Output: `{ taskId, state: 'cancelled', sessionPreserved: true, output, message }`. Because `sessionPreserved: true`, the preserved agent session can be restored later for context, but resume must wait for explicit user instructions before making changes. |
|
|
58
|
+
| `spawn_agent` | — | Start a new child task or send a follow-up to an active task in another repository. Input: `{ sessionId, repo, instruction, role?, context? }`. Output: `{ taskId, message, status: 'delegated' }`. `role` selects the agent slot within the repo (see "Agent roles"). Follow-up routing is automatic per (repo, role): if that (repo, role) already has an active child task, the instruction is delivered to it as a follow-up message; otherwise a new child run starts. A session resume or reconstruction is read-only context restoration; after resuming, do not use `spawn_agent` to continue changes unless the user explicitly asks for changes. |
|
|
59
|
+
| `show_agent` | — | Poll one repo's child status (`repo` required — one repo per call; pass `role` to narrow to that role's agent). Returns `{ children: [...] }` with one self-describing entry per matching agent, exposing `status`, `lastOutputLines`, `role` (absent for the default role), `inputRequiredQuestion`, etc. Full status enum and the poll/state-machine flow are under "Multi-turn tasks". |
|
|
60
|
+
| `stop_agent` | — | Cancel an in-progress child. Input: `{ sessionId, repo, role? }`. Output: `{ taskId, state: 'cancelled', sessionPreserved: true, output, message }`. Because `sessionPreserved: true`, the preserved agent session can be restored later for context, but resume must wait for explicit user instructions before making changes. |
|
|
61
61
|
| `push_branch` | — | Push a local git branch to the remote repository. For the repo you are in, this pushes from your current checkout. Requires a session description. |
|
|
62
62
|
| `create_pr` | — | Create draft PRs with session metadata linking related PRs |
|
|
63
63
|
| `show_session` | `polygraph session show <id> [--details]` | Query status of the current session. Use details when session summary, repo IDs, PR URLs, and PR descriptions are needed. |
|
|
@@ -106,10 +106,10 @@ After logging in (or if logged in but no org is selected), use `polygraph accoun
|
|
|
106
106
|
The delegate/monitor/stop steps apply only when working across repos. A single-repo session skips them and still benefits from shared progress, resume, and CI visibility.
|
|
107
107
|
|
|
108
108
|
0. **Initialize or join Polygraph session** - If you were spawned inside an existing session (the startup banner names a session ID), reuse it. Call `show_session` first; if it already has repos and the user did not ask to add more, you're done. If the user asks to add exact repo refs, call `add_repo` directly with those refs and skip candidate discovery. If the session has no repos and no exact refs were provided, launch the `polygraph-init-subagent` with that `sessionId` so it discovers candidates and uses `add_repo` (NOT `start_session`). Only when there is no session ID at all should the init subagent create a new session.
|
|
109
|
-
1. **Delegate work to each repo** - Use the `polygraph-delegate-subagent` to start child agents in other repositories. Delegate only to *other* repos — never to the repo you are in; work on it directly (your regular subagents are fine for local work — only Polygraph delegation is reserved for other repos). Parallel delegation across repos is encouraged
|
|
109
|
+
1. **Delegate work to each repo** - Use the `polygraph-delegate-subagent` to start child agents in other repositories. Delegate only to *other* repos — never to the repo you are in; work on it directly (your regular subagents are fine for local work — only Polygraph delegation is reserved for other repos). Parallel delegation across repos is encouraged; a repo can also host multiple concurrent agents under distinct roles (see "Agent roles"). Choose the Simple (fire-and-forget) or Multi-turn (interactive) pattern described below based on whether the child may need clarification.
|
|
110
110
|
|
|
111
|
-
4. **Monitor child agents** - Use `show_agent` to poll one repo's
|
|
112
|
-
5. **Stop child agents** (if needed) - Use `stop_agent` to cancel an in-progress child agent. The
|
|
111
|
+
4. **Monitor child agents** - Use `show_agent` to poll one repo's children (`repo` is required; pass `role` to narrow to one agent) and read each entry's `status` and `lastOutputLines` from the `children[]` array.
|
|
112
|
+
5. **Stop child agents** (if needed) - Use `stop_agent` (with `role` when targeting a non-default agent) to cancel an in-progress child agent. The agent's session is preserved for later read-only context restoration; after a resume, wait for explicit user instructions before making changes.
|
|
113
113
|
6. **Push branches** - Use `push_branch` after making commits. A required `description` must follow the Session Description Policy.
|
|
114
114
|
7. **Update session description** - Use `update_session` to update the session description; must follow the Session Description Policy. Independent of PR creation or mark-ready.
|
|
115
115
|
8. **Create draft PRs** - Use `create_pr` to create linked draft PRs. Always pass `description` following the Session Description Policy.
|
|
@@ -252,6 +252,14 @@ polygraph session search --sha a1b2c3d
|
|
|
252
252
|
- Multiple sessions may match a sha. They come back newest first — pick the most relevant one and report the others if they matter.
|
|
253
253
|
- **A "no match" result does NOT prove the commit had no work behind it.** Not every commit is linked to an explicit session: commits pushed directly (rather than via an ingested PR) and gaps in ingestion metadata mean the sha may simply not be recorded, and implicit sessions are never returned. Report "no linked session found for that sha" — never assert that no work exists behind the commit.
|
|
254
254
|
|
|
255
|
+
## Agent roles
|
|
256
|
+
|
|
257
|
+
A repository in a session can host multiple child agents at once, distinguished by **role**:
|
|
258
|
+
|
|
259
|
+
- **Purpose.** Roles let independent streams of work run concurrently in one repo — e.g. a default agent implementing a feature while a `reviewer` or `ci-investigator` runs alongside. Each (repo, role) pair has at most one active child.
|
|
260
|
+
- **Default role.** An omitted `role` means the default role: `spawn_agent` without `role` starts or follows up with the repo's default-role agent.
|
|
261
|
+
- **Logs.** Only default-role agents upload logs to the cloud and appear in the multiplexed log stream (`polygraph session logs`). Inspect non-default agents locally with `polygraph agent attach --role <role>`.
|
|
262
|
+
|
|
255
263
|
## Simple tasks (fire-and-forget)
|
|
256
264
|
|
|
257
265
|
Use this pattern when the task is well-defined and the child is not expected to need clarification. It is a single-round delegation: kick it off, poll until terminal, then push branch + create PR.
|
|
@@ -268,6 +276,7 @@ spawn_agent(
|
|
|
268
276
|
- sessionId: "<session-id>"
|
|
269
277
|
- repo: "<org/repo-name>"
|
|
270
278
|
- instruction: "<the task instruction>"
|
|
279
|
+
- role: "<optional role>"
|
|
271
280
|
- context: "<optional context>"
|
|
272
281
|
|
|
273
282
|
Call the Polygraph MCP spawn_agent for the repo, then poll show_agent via chained waitForTransitionMs long-poll calls until terminal. Return a structured summary with repo, status, session ID, and result text.
|
|
@@ -275,8 +284,8 @@ spawn_agent(
|
|
|
275
284
|
)
|
|
276
285
|
```
|
|
277
286
|
|
|
278
|
-
2. Delegate to multiple repos in parallel by launching multiple `polygraph-delegate-subagent` instances before waiting for results — one delegation per repo at a time.
|
|
279
|
-
3. The subagent watches `child.status` on
|
|
287
|
+
2. Delegate to multiple repos in parallel by launching multiple `polygraph-delegate-subagent` instances before waiting for results — one delegation per (repo, role) at a time.
|
|
288
|
+
3. The subagent watches `child.status` on its delegation's `children[]` entry — the one matching its repo and role — and exits when it sees a terminal status — typically `'completed'` or `'failed'` (and `'cancelled'` if it was stopped).
|
|
280
289
|
4. Collect completed results with `wait_agent` when the main flow needs them, then continue to `push_branch` + `create_pr`.
|
|
281
290
|
|
|
282
291
|
In rare cases where you need to check the raw child agent status directly (e.g., debugging a stuck subagent), you may call the Polygraph MCP `show_agent` as a one-off tool call. Do NOT use this for regular polling — that belongs inside `polygraph-delegate-subagent`.
|
|
@@ -287,13 +296,13 @@ Use Simple when the task is well-defined and the child will not need clarificati
|
|
|
287
296
|
|
|
288
297
|
Use this pattern when the child may need clarification, the task is exploratory, or interactive collaboration is desired. The orchestrator exposes paused children via the `'input-required'` status.
|
|
289
298
|
|
|
290
|
-
1. Call `spawn_agent` with the initial `instruction
|
|
299
|
+
1. Call `spawn_agent` with the initial `instruction` (and optionally `role`). Parse the response:
|
|
291
300
|
|
|
292
301
|
```json
|
|
293
302
|
{ "taskId": "…", "message": "…", "status": "delegated" }
|
|
294
303
|
```
|
|
295
304
|
|
|
296
|
-
2. Poll `show_agent` via chained `waitForTransitionMs` long-poll calls (`repo` is required). The response shape is `{ children: PolygraphChildStatusItem[] }` with
|
|
305
|
+
2. Poll `show_agent` via chained `waitForTransitionMs` long-poll calls (`repo` is required; pass the same `role` you spawned with to narrow to that agent). The response shape is `{ children: PolygraphChildStatusItem[] }` with one entry per matching agent in that repo. On your delegation's entry, inspect:
|
|
297
306
|
|
|
298
307
|
- `child.status` — one of `'created'`, `'in-progress'`, `'input-required'`, `'permission-required'`, `'completed'`, `'failed'`, `'cancelled'` (British double-L on `'cancelled'`).
|
|
299
308
|
- `child.inputRequiredQuestion` — populated only when `child.status === 'input-required'`.
|
|
@@ -303,13 +312,13 @@ Use this pattern when the child may need clarification, the task is exploratory,
|
|
|
303
312
|
Drive the state machine:
|
|
304
313
|
|
|
305
314
|
- `child.status === 'in-progress'` or `'created'` — continue polling.
|
|
306
|
-
- `child.status === 'input-required'` — read `child.inputRequiredQuestion`, surface it to the user verbatim (e.g. "The child agent in `{child.repoFullName}` needs input: {child.inputRequiredQuestion}"), get the answer, then call `spawn_agent` again with the same `repo` and `instruction: <answer>` — it is routed to
|
|
315
|
+
- `child.status === 'input-required'` — read `child.inputRequiredQuestion`, surface it to the user verbatim (e.g. "The child agent in `{child.repoFullName}` needs input: {child.inputRequiredQuestion}"), get the answer, then call `spawn_agent` again with the same `repo`, the same `role`, and `instruction: <answer>` — it is routed to that (repo, role)'s active task automatically. Continue polling.
|
|
307
316
|
- `child.status === 'completed'` — read `child.lastOutputLines`, proceed to `push_branch` + `create_pr`.
|
|
308
317
|
- `child.status === 'failed'` — read `child.lastOutputLines`, surface the failure.
|
|
309
318
|
- `child.status === 'cancelled'` — the child was stopped via `stop_agent`; see below.
|
|
310
319
|
- `child.status === 'permission-required'` — the child is waiting on a permission decision; see "Handling permission requests" below.
|
|
311
320
|
|
|
312
|
-
3. To abort mid-flight, call `stop_agent` with `{ sessionId, repo }`. The response is:
|
|
321
|
+
3. To abort mid-flight, call `stop_agent` with `{ sessionId, repo, role? }`. The response is:
|
|
313
322
|
|
|
314
323
|
```json
|
|
315
324
|
{
|
|
@@ -321,7 +330,7 @@ Use this pattern when the child may need clarification, the task is exploratory,
|
|
|
321
330
|
}
|
|
322
331
|
```
|
|
323
332
|
|
|
324
|
-
Because `sessionPreserved: true`, the
|
|
333
|
+
Because `sessionPreserved: true`, the stopped agent's session can be restored later for context. After resuming, do not make changes or continue prior work until the user explicitly asks for changes.
|
|
325
334
|
|
|
326
335
|
Use Multi-turn when the child may need clarification, the task is exploratory, or interactive collaboration is desired. Otherwise use Simple.
|
|
327
336
|
|
|
@@ -340,26 +349,11 @@ If you call `allow_agent` while the dialog is already open, you create a race: t
|
|
|
340
349
|
|
|
341
350
|
The `allow_agent` and `deny_agent` tools exist for parents whose MCP clients do NOT advertise elicitation capability (opencode TUI today). They are not part of your flow.
|
|
342
351
|
|
|
343
|
-
### 2. Push Branches
|
|
352
|
+
### 2. Publish Changes (Push Branches, Create PRs, Mark Ready)
|
|
344
353
|
|
|
345
|
-
|
|
354
|
+
Publishing covers the branch-to-PR flow: `push_branch` (push local commits; must precede PR creation), `create_pr` (linked draft PRs, including fork PRs via `targetRepository`), `mark_pr_ready` (transition drafts to OPEN), and `associate_pr` (link PRs created outside Polygraph).
|
|
346
355
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
**Parameters:**
|
|
350
|
-
|
|
351
|
-
- `sessionId` (required): The Polygraph session ID
|
|
352
|
-
- `repo` (required): Repository name or repository ID to push from
|
|
353
|
-
- `branch` (required): Branch name to push to remote
|
|
354
|
-
- `description` (required): A session description is required. Must follow the Session Description Policy.
|
|
355
|
-
|
|
356
|
-
```
|
|
357
|
-
push_branch(
|
|
358
|
-
sessionId: "<session-id>",
|
|
359
|
-
repo: "org/repo-name",
|
|
360
|
-
branch: "polygraph/ad5fa-add-user-preferences"
|
|
361
|
-
)
|
|
362
|
-
```
|
|
356
|
+
**Whenever you push a branch, create or associate a PR, or mark PRs ready, read [`reference/publish-changes.md`](reference/publish-changes.md) first.** That reference file holds the full flow: parameters and examples for each tool, `push_branch` local-checkout semantics, the PR title format rules, and the session-URL printing steps. `push_branch`, `create_pr`, and `associate_pr` all require a `description` following the Session Description Policy below.
|
|
363
357
|
|
|
364
358
|
### Session Description Policy
|
|
365
359
|
|
|
@@ -367,121 +361,18 @@ push_branch(
|
|
|
367
361
|
|
|
368
362
|
**Whenever you write or update a session description, read [`reference/session-description.md`](reference/session-description.md) first.** That reference file holds the full policy: the canonical Markdown-heading template (`## Goal` / `## Current progress` / `## What worked` / `## Next steps`), the dual-audience guidance (humans in the web UI now, agents reconstructing history later), and the formatting building blocks the app renders (callouts, tables, mermaid, links, `link_reference`).
|
|
369
363
|
|
|
370
|
-
### 3.
|
|
371
|
-
|
|
372
|
-
Create PRs for all repositories at once using `create_pr`. PRs are created as drafts with session metadata that links related PRs across repos. Branches must be pushed first. For fork PR creation or registration, include `targetRepository` on the PR spec to identify the repository that should receive the PR.
|
|
373
|
-
|
|
374
|
-
**Parameters:**
|
|
375
|
-
|
|
376
|
-
- `sessionId` (required): The Polygraph session ID
|
|
377
|
-
- `prs` (required): Array of PR specifications, each containing:
|
|
378
|
-
- `owner` (required): GitHub repository owner
|
|
379
|
-
- `repo` (required): GitHub repository name
|
|
380
|
-
- `title` (required): PR title
|
|
381
|
-
- `body` (required): PR description (session metadata is appended automatically)
|
|
382
|
-
- `branch` (required): Branch name that was pushed
|
|
383
|
-
- `targetRepository` (optional): Target GitHub repository for fork PR creation or registration, as `owner/repo`. Omit for same-repository PRs.
|
|
384
|
-
- `description` (required): Must follow the Session Description Policy.
|
|
385
|
-
|
|
386
|
-
**PR title format (applies to parent and child agents):**
|
|
364
|
+
### 3. Get Current Polygraph Session
|
|
387
365
|
|
|
388
|
-
|
|
389
|
-
- Do NOT add agent-identifier prefixes such as `[codex]`, `[claude]`, or `[opencode]` to PR titles. These prefixes violate commit-lint rules and pollute the git history.
|
|
390
|
-
|
|
391
|
-
```
|
|
392
|
-
create_pr(
|
|
393
|
-
sessionId: "<session-id>",
|
|
394
|
-
prs: [
|
|
395
|
-
{
|
|
396
|
-
owner: "org",
|
|
397
|
-
repo: "frontend",
|
|
398
|
-
title: "feat: Add user preferences UI",
|
|
399
|
-
body: "Part of multi-repo user preferences feature",
|
|
400
|
-
branch: "polygraph/ad5fa-add-user-preferences"
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
owner: "org",
|
|
404
|
-
repo: "backend",
|
|
405
|
-
title: "feat: Add user preferences API",
|
|
406
|
-
body: "Part of multi-repo user preferences feature",
|
|
407
|
-
branch: "polygraph/ad5fa-add-user-preferences"
|
|
408
|
-
}
|
|
409
|
-
]
|
|
410
|
-
)
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
For fork PR creation or registration, keep `owner` and `repo` set to the source repository that owns the pushed branch and set `targetRepository` to the target repository:
|
|
414
|
-
|
|
415
|
-
```
|
|
416
|
-
create_pr(
|
|
417
|
-
sessionId: "<session-id>",
|
|
418
|
-
prs: [
|
|
419
|
-
{
|
|
420
|
-
owner: "contributor",
|
|
421
|
-
repo: "frontend-fork",
|
|
422
|
-
targetRepository: "org/frontend",
|
|
423
|
-
title: "feat: Add user preferences UI",
|
|
424
|
-
body: "Part of multi-repo user preferences feature",
|
|
425
|
-
branch: "polygraph/ad5fa-add-user-preferences"
|
|
426
|
-
}
|
|
427
|
-
]
|
|
428
|
-
)
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
**After creating PRs**, always print the Polygraph session URL:
|
|
432
|
-
|
|
433
|
-
```
|
|
434
|
-
**Polygraph session:** POLYGRAPH_SESSION_URL
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### 4. Get Current Polygraph Session
|
|
438
|
-
|
|
439
|
-
Check the details of a session using `show_session` or `polygraph session show --details <session-id>`. Returns the full session state including repositories, PRs, CI status, and the Polygraph session URL.
|
|
366
|
+
Check the details of a session using `show_session` or `polygraph session show --details <session-id>`. Returns the full session state — basic metadata like id, url & description timeline, plus the connected repositories, `pullRequests[]`, per-PR `ciStatus`, and `session.linkedReferences`.
|
|
440
367
|
|
|
441
368
|
**Parameters:**
|
|
442
369
|
|
|
443
370
|
- `sessionId` (required): The Polygraph session ID
|
|
444
371
|
|
|
445
|
-
**
|
|
372
|
+
**CI status rules:**
|
|
446
373
|
|
|
447
|
-
- `
|
|
448
|
-
- `
|
|
449
|
-
- `session.description`: DescriptionItem[] timeline describing the session.
|
|
450
|
-
- `session.agentSessionId`: The agent CLI session ID — captured automatically by the MCP server (null if no agent has run yet).
|
|
451
|
-
- `session.linkedReferences`: Array of references linked to this session
|
|
452
|
-
- Session repository entries: Array of connected repositories, each with:
|
|
453
|
-
- `id`: Repository ID
|
|
454
|
-
- `name`: Repository name
|
|
455
|
-
- `defaultBranch`: Default branch (e.g., `main`)
|
|
456
|
-
- `vcsConfiguration.repositoryFullName`: Full repo name (e.g., `org/repo`)
|
|
457
|
-
- `vcsConfiguration.provider`: VCS provider (e.g., `GITHUB`)
|
|
458
|
-
- description field: AI-generated description of what this repository does (may be null)
|
|
459
|
-
- `initiator`: Whether this repository initiated the session
|
|
460
|
-
- `session.dependencyGraph`: Graph of repository dependency `edges`
|
|
461
|
-
- `session.pullRequests[]`: Array of PRs, each with:
|
|
462
|
-
- `url`: PR URL
|
|
463
|
-
- `branch`: Branch name
|
|
464
|
-
- `baseBranch`: Target branch
|
|
465
|
-
- `title`: PR title
|
|
466
|
-
- `status`: One of `DRAFT`, `OPEN`, `MERGED`, `CLOSED`
|
|
467
|
-
- `repoId`: Associated repository ID
|
|
468
|
-
- `relatedPRs`: Array of related PR URLs across repos
|
|
469
|
-
- `session.ciStatus`: CI pipeline status keyed by PR ID, each containing:
|
|
470
|
-
- `status`: One of `SUCCEEDED`, `FAILED`, `IN_PROGRESS`, `NOT_STARTED` (null if no CIPE and no external CI)
|
|
471
|
-
- `cipeUrl`: URL to the CI pipeline execution details (null if no CIPE). This is a human-facing Nx Cloud web link — display it to the user, but never fetch, curl, or poll it directly; CIPE data is only accessible programmatically via the Nx MCP `ci_information` tool
|
|
472
|
-
- `completedAt`: Epoch millis timestamp, set only when the CIPE has completed (null otherwise)
|
|
473
|
-
- `selfHealingStatus`: The self-healing fix status string from Nx Cloud's AI fix feature (null if no AI fix exists)
|
|
474
|
-
- `externalCIRuns`: Array of external CI runs (present when no CIPE but external CI data exists, e.g., GitHub Actions). Each run contains:
|
|
475
|
-
- `runId`: GitHub Actions run ID
|
|
476
|
-
- `name`: Workflow name
|
|
477
|
-
- `status`: Run status (`completed`, `in_progress`, `queued`)
|
|
478
|
-
- `conclusion`: Run conclusion (`success`, `failure`, `cancelled`, `timed_out`, or null)
|
|
479
|
-
- `url`: GitHub Actions run URL
|
|
480
|
-
- `jobs`: Array of jobs in the run, each with:
|
|
481
|
-
- `jobId`: Job ID (use with `get_ci_logs`)
|
|
482
|
-
- `name`: Job name
|
|
483
|
-
- `status`: Job status
|
|
484
|
-
- `conclusion`: Job conclusion (or null)
|
|
374
|
+
- `ciStatus[prId].cipeUrl` (null if no CIPE) is a human-facing Nx Cloud web link — display it to the user, but never fetch, curl, or poll it directly; CIPE data is only accessible programmatically via the Nx MCP `ci_information` tool.
|
|
375
|
+
- When no CIPE exists, external CI data (e.g., GitHub Actions) appears in `ciStatus[prId].externalCIRuns[]` as runs with nested `jobs[]`; each job's `jobId` is the input for `get_ci_logs`.
|
|
485
376
|
|
|
486
377
|
```
|
|
487
378
|
show_session(sessionId: "<session-id>")
|
|
@@ -528,67 +419,7 @@ link_reference({
|
|
|
528
419
|
|
|
529
420
|
The canonical MCP parameters are `{ sessionId, reference }`. There is no unlink command.
|
|
530
421
|
|
|
531
|
-
###
|
|
532
|
-
|
|
533
|
-
Once all changes are verified and ready to merge, use `mark_pr_ready` to transition PRs from DRAFT to OPEN status.
|
|
534
|
-
|
|
535
|
-
**Parameters:**
|
|
536
|
-
|
|
537
|
-
- `sessionId` (required): The Polygraph session ID
|
|
538
|
-
- `prUrls` (required): Array of PR URLs to mark as ready for review
|
|
539
|
-
|
|
540
|
-
```
|
|
541
|
-
mark_pr_ready(
|
|
542
|
-
sessionId: "<session-id>",
|
|
543
|
-
prUrls: [
|
|
544
|
-
"https://github.com/org/frontend/pull/123",
|
|
545
|
-
"https://github.com/org/backend/pull/456"
|
|
546
|
-
]
|
|
547
|
-
)
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
**After marking PRs as ready**, always print the Polygraph session URL so the user can easily access the session overview. Call `show_session` and display:
|
|
551
|
-
|
|
552
|
-
```
|
|
553
|
-
**Polygraph session:** POLYGRAPH_SESSION_URL
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
Where `POLYGRAPH_SESSION_URL` is from `polygraphSessionUrl` in the response.
|
|
557
|
-
|
|
558
|
-
### 6. Associate Existing PRs
|
|
559
|
-
|
|
560
|
-
Use `associate_pr` to link pull requests that were created outside of Polygraph (e.g., manually or by CI) to the current session. This is useful when PRs already exist for the branches in the session and you want Polygraph to track them.
|
|
561
|
-
|
|
562
|
-
Provide either a `prUrl` to associate a specific PR, or a `branch` name plus `repo` to find and associate PRs for a source repository.
|
|
563
|
-
|
|
564
|
-
**Parameters:**
|
|
565
|
-
|
|
566
|
-
- `sessionId` (required): The Polygraph session ID
|
|
567
|
-
- `prUrl` (optional): URL of an existing pull request to associate
|
|
568
|
-
- `branch` (optional): Branch name to find and associate PRs for
|
|
569
|
-
- `repo` (optional): Source repository for branch-based association. Required when using `branch` in a multi-repo session.
|
|
570
|
-
- `description` (required): Must follow the Session Description Policy.
|
|
571
|
-
|
|
572
|
-
```
|
|
573
|
-
associate_pr(
|
|
574
|
-
sessionId: "<session-id>",
|
|
575
|
-
prUrl: "https://github.com/org/repo/pull/123"
|
|
576
|
-
)
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
Or by branch:
|
|
580
|
-
|
|
581
|
-
```
|
|
582
|
-
associate_pr(
|
|
583
|
-
sessionId: "<session-id>",
|
|
584
|
-
repo: "org/repo",
|
|
585
|
-
branch: "feature/my-changes"
|
|
586
|
-
)
|
|
587
|
-
```
|
|
588
|
-
|
|
589
|
-
**Returns** the list of PRs now associated with the session.
|
|
590
|
-
|
|
591
|
-
### 7. Add Repositories to a Session
|
|
422
|
+
### 4. Add Repositories to a Session
|
|
592
423
|
|
|
593
424
|
Use `add_repo` to add repositories to an existing Polygraph session after it has already started.
|
|
594
425
|
|
|
@@ -608,7 +439,7 @@ add_repo(
|
|
|
608
439
|
)
|
|
609
440
|
```
|
|
610
441
|
|
|
611
|
-
###
|
|
442
|
+
### 5. Archive Session
|
|
612
443
|
|
|
613
444
|
**IMPORTANT: Only call this tool when the user explicitly asks to archive or close the session.** Do not archive sessions automatically as part of the workflow.
|
|
614
445
|
|
|
@@ -722,7 +553,7 @@ If the session has a description timeline, also display:
|
|
|
722
553
|
|
|
723
554
|
1. **NEVER call the Polygraph MCP `spawn_agent` or `show_agent` directly for routine delegation**. These MUST run inside `polygraph-delegate-subagent`.
|
|
724
555
|
|
|
725
|
-
1. **Use `stop_agent` to clean up** — Stop child agents that are stuck or no longer needed. The child's session is preserved (`sessionPreserved: true`) so the context can be restored later, but after resuming you must wait for explicit user instructions before making changes.
|
|
556
|
+
1. **Use `stop_agent` to clean up** — Stop child agents that are stuck or no longer needed (pass `role` to target a non-default agent). The child's session is preserved (`sessionPreserved: true`) so the context can be restored later, but after resuming you must wait for explicit user instructions before making changes.
|
|
726
557
|
1. **Only archive sessions when asked** — Only call `archive_session` when the user explicitly requests it. Archiving hides the session from active lists; it can still be resumed later.
|
|
727
558
|
|
|
728
559
|
1. **Respect the sandbox** — When a command fails with a sandbox denial (`EPERM` binding a port, blocked host, denied write), stop instead of retrying and point the user to the options in "Sandboxing in Polygraph Sessions": commit harness sandbox settings to the repo, or toggle sandboxing via `polygraph config`.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Publishing Changes Reference
|
|
2
|
+
|
|
3
|
+
The branch-to-PR flow: push branches, create draft PRs, mark them ready, and associate PRs created outside Polygraph. `push_branch`, `create_pr`, and `associate_pr` all require a `description` following the Session Description Policy — read [`session-description.md`](session-description.md) before writing one.
|
|
4
|
+
|
|
5
|
+
## Push Branches
|
|
6
|
+
|
|
7
|
+
Once work is complete in a repository, push the branch using `push_branch`. This must be done before creating a PR.
|
|
8
|
+
|
|
9
|
+
`push_branch` pushes from the local checkout: for the repo you are in, that is your current working directory with your commits; for delegated repos, it is the Polygraph-managed clone the child agent worked in. There is no separate session copy of the current repo.
|
|
10
|
+
|
|
11
|
+
**Parameters:**
|
|
12
|
+
|
|
13
|
+
- `sessionId` (required): The Polygraph session ID
|
|
14
|
+
- `repo` (required): Repository name or repository ID to push from
|
|
15
|
+
- `branch` (required): Branch name to push to remote
|
|
16
|
+
- `description` (required): A session description is required. Must follow the Session Description Policy.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
push_branch(
|
|
20
|
+
sessionId: "<session-id>",
|
|
21
|
+
repo: "org/repo-name",
|
|
22
|
+
branch: "polygraph/ad5fa-add-user-preferences"
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Create Draft PRs
|
|
27
|
+
|
|
28
|
+
Create PRs for all repositories at once using `create_pr`. PRs are created as drafts with session metadata that links related PRs across repos. Branches must be pushed first. For fork PR creation or registration, include `targetRepository` on the PR spec to identify the repository that should receive the PR.
|
|
29
|
+
|
|
30
|
+
**Parameters:**
|
|
31
|
+
|
|
32
|
+
- `sessionId` (required): The Polygraph session ID
|
|
33
|
+
- `prs` (required): Array of PR specifications, each containing:
|
|
34
|
+
- `owner` (required): GitHub repository owner
|
|
35
|
+
- `repo` (required): GitHub repository name
|
|
36
|
+
- `title` (required): PR title
|
|
37
|
+
- `body` (required): PR description (session metadata is appended automatically)
|
|
38
|
+
- `branch` (required): Branch name that was pushed
|
|
39
|
+
- `targetRepository` (optional): Target GitHub repository for fork PR creation or registration, as `owner/repo`. Omit for same-repository PRs.
|
|
40
|
+
- `description` (required): Must follow the Session Description Policy.
|
|
41
|
+
|
|
42
|
+
**PR title format (applies to parent and child agents):**
|
|
43
|
+
|
|
44
|
+
- PR titles become squash-merge commit messages in most repos. They MUST follow the target repo's commit convention (e.g., Conventional Commits: `<type>(<scope>): <subject>`).
|
|
45
|
+
- Do NOT add agent-identifier prefixes such as `[codex]`, `[claude]`, or `[opencode]` to PR titles. These prefixes violate commit-lint rules and pollute the git history.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
create_pr(
|
|
49
|
+
sessionId: "<session-id>",
|
|
50
|
+
prs: [
|
|
51
|
+
{
|
|
52
|
+
owner: "org",
|
|
53
|
+
repo: "frontend",
|
|
54
|
+
title: "feat: Add user preferences UI",
|
|
55
|
+
body: "Part of multi-repo user preferences feature",
|
|
56
|
+
branch: "polygraph/ad5fa-add-user-preferences"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
owner: "org",
|
|
60
|
+
repo: "backend",
|
|
61
|
+
title: "feat: Add user preferences API",
|
|
62
|
+
body: "Part of multi-repo user preferences feature",
|
|
63
|
+
branch: "polygraph/ad5fa-add-user-preferences"
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For fork PR creation or registration, keep `owner` and `repo` set to the source repository that owns the pushed branch and set `targetRepository` to the target repository:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
create_pr(
|
|
73
|
+
sessionId: "<session-id>",
|
|
74
|
+
prs: [
|
|
75
|
+
{
|
|
76
|
+
owner: "contributor",
|
|
77
|
+
repo: "frontend-fork",
|
|
78
|
+
targetRepository: "org/frontend",
|
|
79
|
+
title: "feat: Add user preferences UI",
|
|
80
|
+
body: "Part of multi-repo user preferences feature",
|
|
81
|
+
branch: "polygraph/ad5fa-add-user-preferences"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**After creating PRs**, always print the Polygraph session URL:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
**Polygraph session:** POLYGRAPH_SESSION_URL
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Mark PRs Ready
|
|
94
|
+
|
|
95
|
+
Once all changes are verified and ready to merge, use `mark_pr_ready` to transition PRs from DRAFT to OPEN status.
|
|
96
|
+
|
|
97
|
+
**Parameters:**
|
|
98
|
+
|
|
99
|
+
- `sessionId` (required): The Polygraph session ID
|
|
100
|
+
- `prUrls` (required): Array of PR URLs to mark as ready for review
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
mark_pr_ready(
|
|
104
|
+
sessionId: "<session-id>",
|
|
105
|
+
prUrls: [
|
|
106
|
+
"https://github.com/org/frontend/pull/123",
|
|
107
|
+
"https://github.com/org/backend/pull/456"
|
|
108
|
+
]
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**After marking PRs as ready**, always print the Polygraph session URL so the user can easily access the session overview. Call `show_session` and display:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
**Polygraph session:** POLYGRAPH_SESSION_URL
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Where `POLYGRAPH_SESSION_URL` is from `polygraphSessionUrl` in the response.
|
|
119
|
+
|
|
120
|
+
## Associate Existing PRs
|
|
121
|
+
|
|
122
|
+
Use `associate_pr` to link pull requests that were created outside of Polygraph (e.g., manually or by CI) to the current session. This is useful when PRs already exist for the branches in the session and you want Polygraph to track them.
|
|
123
|
+
|
|
124
|
+
Provide either a `prUrl` to associate a specific PR, or a `branch` name plus `repo` to find and associate PRs for a source repository.
|
|
125
|
+
|
|
126
|
+
**Parameters:**
|
|
127
|
+
|
|
128
|
+
- `sessionId` (required): The Polygraph session ID
|
|
129
|
+
- `prUrl` (optional): URL of an existing pull request to associate
|
|
130
|
+
- `branch` (optional): Branch name to find and associate PRs for
|
|
131
|
+
- `repo` (optional): Source repository for branch-based association. Required when using `branch` in a multi-repo session.
|
|
132
|
+
- `description` (required): Must follow the Session Description Policy.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
associate_pr(
|
|
136
|
+
sessionId: "<session-id>",
|
|
137
|
+
prUrl: "https://github.com/org/repo/pull/123"
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Or by branch:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
associate_pr(
|
|
145
|
+
sessionId: "<session-id>",
|
|
146
|
+
repo: "org/repo",
|
|
147
|
+
branch: "feature/my-changes"
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Returns** the list of PRs now associated with the session.
|
|
@@ -26,7 +26,7 @@ Invoke the CLI as `${POLYGRAPH_CLI:-polygraph}` in every command: when the sessi
|
|
|
26
26
|
|
|
27
27
|
1. `${POLYGRAPH_CLI:-polygraph} session show --details <sessionId>` — metadata, description timeline, repositories, PRs. The description timeline often already summarizes goals and outcomes; mine it before reading transcripts.
|
|
28
28
|
2. Duplicate-work check: if the metadata shows this session pursuing the SAME task as the current one (not merely related work) and it is unfinished or recently active, do NOT read the transcripts. Return the debrief section immediately, with `**DUPLICATE WORK IN FLIGHT**` as the first line after the heading, followed by the session's status and last activity, one line of evidence for the match, and what resuming it would restore. The parent halts and asks the user to choose between resuming that session and continuing the current one, so speed matters more than depth here.
|
|
29
|
-
3. `${POLYGRAPH_CLI:-polygraph} session logs -s <sessionId> --all --tail none > "$TMPDIR/<sessionId>-logs.txt" 2>&1` — the parent transcript plus every child transcript, rendered as plain text, in ONE call. Then read the file directly (with offsets for large files). Do NOT fetch `--json` and do NOT query the transcript with node/python one-liners — reading the rendered text is faster and you extract while reading.
|
|
29
|
+
3. `${POLYGRAPH_CLI:-polygraph} session logs -s <sessionId> --all --tail none > "$TMPDIR/<sessionId>-logs.txt" 2>&1` — the parent transcript plus every child transcript, rendered as plain text, in ONE call. Then read the file directly (with offsets for large files). Do NOT fetch `--json` and do NOT query the transcript with node/python one-liners — reading the rendered text is faster and you extract while reading. **Coverage caveat:** `session logs --all` covers default-role children only — agents spawned with a `role` keep their transcripts local to the machine that ran them (viewable there via `polygraph agent attach --role <role>`); if the session used such agents, note in the debrief that their work is not visible in these logs.
|
|
30
30
|
4. Write the debrief section (format below).
|
|
31
31
|
|
|
32
32
|
Large transcripts: read the file in a few large chunks, prioritizing user prompts, assistant text and final messages, tool errors and failure events, and task notifications. Routine tool-use noise (file reads, searches) is safe to skim. Do not make repeated small queries against the transcript; each round trip costs more than reading a bigger chunk.
|