syntaur 0.70.0 → 0.72.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.
- package/.claude-plugin/plugin.json +1 -1
- package/dashboard/dist/assets/{_basePickBy-DKk6tHtk.js → _basePickBy-QfpY8LS2.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-DM-f7DWz.js → _baseUniq-J2dp0xSF.js} +1 -1
- package/dashboard/dist/assets/{arc-ZBlA3YdV.js → arc-7V3bSBdi.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-BUmvtGTF.js → architectureDiagram-2XIMDMQ5-L4xF7_w_.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-B3qxWK6s.js → blockDiagram-WCTKOSBZ-D85LV89B.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-BEq_UJO-.js → c4Diagram-IC4MRINW-BuLOHFHk.js} +1 -1
- package/dashboard/dist/assets/channel-BPiUfFXP.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-C-Y9ryMm.js → chunk-4BX2VUAB-PMmPIfmW.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-CGdtbsjw.js → chunk-55IACEB6-CuzXx0Ve.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-DllxJhUp.js → chunk-FMBD7UC4-DgbPJiW4.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-jjMM8O5F.js → chunk-JSJVCQXG-BIdP1PgR.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-B_6BPltQ.js → chunk-KX2RTZJC-Jx0-O-nW.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-D0hJiXHp.js → chunk-NQ4KR5QH-CZy5XF4L.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-BCWo4hLS.js → chunk-QZHKN3VN-Clgnd2ni.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-DH_jEAwg.js → chunk-WL4C6EOR-DItFgUMd.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-HDWgoi6J.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-HDWgoi6J.js +1 -0
- package/dashboard/dist/assets/clone-BdrN_Gqo.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-5ld00TOH.js → cose-bilkent-S5V4N54A-CdvW6L_R.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-Cnu6eQWy.js → dagre-KLK3FWXG-200WRn9D.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-_CBBKNP-.js → diagram-E7M64L7V-B_4QJiws.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-DE6WjIb1.js → diagram-IFDJBPK2-DiSnANLV.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-DpW7UzNK.js → diagram-P4PSJMXO-DjtHY2zM.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-BD2409fE.js → erDiagram-INFDFZHY-032TAwXT.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-1p0khhFI.js → flowDiagram-PKNHOUZH-DGNPxjzE.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-B2zFyA4s.js → ganttDiagram-A5KZAMGK-BjbxtEVv.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-bH-4YH7h.js → gitGraphDiagram-K3NZZRJ6-CgFktzLw.js} +1 -1
- package/dashboard/dist/assets/{graph-BT24B6iQ.js → graph-CyuCoTKt.js} +1 -1
- package/dashboard/dist/assets/{index-Cxqr3rQB.js → index-DsFBSYQj.js} +102 -102
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-CMzP4Hcg.js → infoDiagram-LFFYTUFH-Dav72O_U.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DMEmFC7M.js → ishikawaDiagram-PHBUUO56-RAyYfa7q.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-CAtzYQUm.js → journeyDiagram-4ABVD52K-D_9LHvxq.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-d1JVbtvX.js → kanban-definition-K7BYSVSG-BxawyHsy.js} +1 -1
- package/dashboard/dist/assets/{layout-BVuI38I_.js → layout-BuWGns-1.js} +1 -1
- package/dashboard/dist/assets/{linear-Bc8PGMbp.js → linear-Dml-S448.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-UtwFYLNj.js → mermaid.core-p144DJAn.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-DHc5RCDj.js → mindmap-definition-YRQLILUH-ffX-VsIz.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-9anIsdIA.js → pieDiagram-SKSYHLDU-CneGfBsg.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-FZ0D9HnU.js → quadrantDiagram-337W2JSQ-B1fvKMwB.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-BkjCvH_u.js → requirementDiagram-Z7DCOOCP-B-rOBvHF.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-DzqwYHDo.js → sankeyDiagram-WA2Y5GQK-Bb_m_ROm.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-BW4g5Ao-.js → sequenceDiagram-2WXFIKYE-B-H6H5KN.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-D0tKU3Z0.js → stateDiagram-RAJIS63D-CsDEjjit.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DmheKY2h.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-Bu269QDX.js → timeline-definition-YZTLITO2-d0zf4ELB.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-BGu_rrva.js → treemap-KZPCXAKY-DZZjDZEs.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-Cx_n5FRZ.js → vennDiagram-LZ73GAT5-CoxX9DoM.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BOJsKV_W.js → xychartDiagram-JWTSCODW-BN1K72KM.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/dashboard/server.js +1385 -540
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +2770 -1535
- package/dist/index.js.map +1 -1
- package/dist/launch/index.js +594 -109
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/claude-code/hooks/enforce-boundaries.sh +49 -16
- package/platforms/claude-code/hooks/session-cleanup.sh +4 -2
- package/platforms/claude-code/skills/add-memory/SKILL.md +3 -2
- package/platforms/claude-code/skills/add-resource/SKILL.md +3 -2
- package/platforms/claude-code/skills/bundle-worktree/SKILL.md +3 -3
- package/platforms/claude-code/skills/capture-artifacts/SKILL.md +2 -2
- package/platforms/claude-code/skills/claim-resource/SKILL.md +3 -3
- package/platforms/claude-code/skills/clear-assignment/SKILL.md +9 -27
- package/platforms/claude-code/skills/complete-assignment/SKILL.md +3 -3
- package/platforms/claude-code/skills/create-assignment/SKILL.md +2 -2
- package/platforms/claude-code/skills/extend-resource/SKILL.md +2 -2
- package/platforms/claude-code/skills/grab-assignment/SKILL.md +17 -12
- package/platforms/claude-code/skills/grab-bundle/SKILL.md +10 -6
- package/platforms/claude-code/skills/log-progress/SKILL.md +6 -4
- package/platforms/claude-code/skills/plan-assignment/SKILL.md +3 -3
- package/platforms/claude-code/skills/plan-bundle/SKILL.md +4 -3
- package/platforms/claude-code/skills/replan/SKILL.md +9 -6
- package/platforms/claude-code/skills/resume-session/SKILL.md +14 -8
- package/platforms/claude-code/skills/save-session-summary/SKILL.md +4 -4
- package/platforms/claude-code/skills/set-workspace/SKILL.md +9 -6
- package/platforms/claude-code/skills/syntaur-protocol/SKILL.md +9 -7
- package/platforms/claude-code/skills/syntaur-protocol/references/file-ownership.md +1 -1
- package/platforms/claude-code/skills/syntaur-worktree/SKILL.md +11 -7
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/codex/scripts/enforce-boundaries.sh +74 -12
- package/platforms/codex/scripts/session-cleanup.sh +20 -13
- package/platforms/codex/skills/add-memory/SKILL.md +3 -2
- package/platforms/codex/skills/add-resource/SKILL.md +3 -2
- package/platforms/codex/skills/bundle-worktree/SKILL.md +3 -3
- package/platforms/codex/skills/capture-artifacts/SKILL.md +2 -2
- package/platforms/codex/skills/claim-resource/SKILL.md +3 -3
- package/platforms/codex/skills/clear-assignment/SKILL.md +9 -27
- package/platforms/codex/skills/complete-assignment/SKILL.md +3 -3
- package/platforms/codex/skills/create-assignment/SKILL.md +2 -2
- package/platforms/codex/skills/extend-resource/SKILL.md +2 -2
- package/platforms/codex/skills/grab-assignment/SKILL.md +17 -12
- package/platforms/codex/skills/grab-bundle/SKILL.md +10 -6
- package/platforms/codex/skills/log-progress/SKILL.md +6 -4
- package/platforms/codex/skills/plan-assignment/SKILL.md +3 -3
- package/platforms/codex/skills/plan-bundle/SKILL.md +4 -3
- package/platforms/codex/skills/replan/SKILL.md +9 -6
- package/platforms/codex/skills/resume-session/SKILL.md +14 -8
- package/platforms/codex/skills/save-session-summary/SKILL.md +4 -4
- package/platforms/codex/skills/set-workspace/SKILL.md +9 -6
- package/platforms/codex/skills/syntaur-protocol/SKILL.md +9 -7
- package/platforms/codex/skills/syntaur-protocol/references/file-ownership.md +1 -1
- package/platforms/codex/skills/syntaur-worktree/SKILL.md +11 -7
- package/platforms/hermes/plugins/syntaur/__init__.py +29 -3
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/boundary.py +18 -9
- package/platforms/pi/extensions/syntaur/index.ts +84 -29
- package/skills/add-memory/SKILL.md +3 -2
- package/skills/add-resource/SKILL.md +3 -2
- package/skills/bundle-worktree/SKILL.md +3 -3
- package/skills/capture-artifacts/SKILL.md +2 -2
- package/skills/claim-resource/SKILL.md +3 -3
- package/skills/clear-assignment/SKILL.md +9 -27
- package/skills/complete-assignment/SKILL.md +3 -3
- package/skills/create-assignment/SKILL.md +2 -2
- package/skills/extend-resource/SKILL.md +2 -2
- package/skills/grab-assignment/SKILL.md +17 -12
- package/skills/grab-bundle/SKILL.md +10 -6
- package/skills/log-progress/SKILL.md +6 -4
- package/skills/plan-assignment/SKILL.md +3 -3
- package/skills/plan-bundle/SKILL.md +4 -3
- package/skills/replan/SKILL.md +9 -6
- package/skills/resume-session/SKILL.md +14 -8
- package/skills/save-session-summary/SKILL.md +4 -4
- package/skills/set-workspace/SKILL.md +9 -6
- package/skills/syntaur-protocol/SKILL.md +9 -7
- package/skills/syntaur-protocol/references/file-ownership.md +1 -1
- package/skills/syntaur-worktree/SKILL.md +11 -7
- package/dashboard/dist/assets/channel-fypxffzQ.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-1KnjQvtL.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-1KnjQvtL.js +0 -1
- package/dashboard/dist/assets/clone-CKMabBhS.js +0 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DxWQhjNO.js +0 -1
|
@@ -32,7 +32,7 @@ Respect file ownership boundaries. The Claude Code and Codex plugins enforce the
|
|
|
32
32
|
- `~/.syntaur/projects/<project>/resources/<slug>.md`
|
|
33
33
|
- `~/.syntaur/projects/<project>/memories/<slug>.md`
|
|
34
34
|
3. **Workspace files** inside the assignment's configured `workspace.worktreePath` / `workspace.repository`.
|
|
35
|
-
4. **
|
|
35
|
+
4. **Workspace marker:** `.syntaur/context.json` in the current working directory (repository/branch/worktree markers plus legacy session/lease bookkeeping — not the active-assignment source of truth).
|
|
36
36
|
|
|
37
37
|
### Files written only via CLI (never edit directly)
|
|
38
38
|
|
|
@@ -51,16 +51,18 @@ Per-project `agent.md` / `claude.md` do NOT exist in protocol v2.0. Agent-level
|
|
|
51
51
|
|
|
52
52
|
## Current Assignment Context
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
The **active assignment** is resolved from the session's OPEN engagement — the assignment this session is currently bound to (established by `syntaur track-session`). It is NOT read from `.syntaur/context.json`. To learn the active assignment, run `syntaur session resume` (or `--json`); to bind a different one, `grab-assignment` (which calls `track-session`).
|
|
55
55
|
|
|
56
|
-
- `projectSlug`
|
|
57
|
-
|
|
58
|
-
- `
|
|
59
|
-
- `
|
|
56
|
+
`.syntaur/context.json` is a WORKSPACE MARKER file — it identifies the workspace directory and carries legacy session and resource-lease bookkeeping. It is NOT authoritative for the active assignment. Read it for workspace markers and leases; do NOT treat `projectSlug` / `assignmentSlug` / `assignmentDir` as the active-assignment source of truth (any such scalars are non-authoritative legacy hints). Fields you may see:
|
|
57
|
+
|
|
58
|
+
- `repository` — workspace repository (path or remote URL)
|
|
59
|
+
- `branch` — workspace branch, if known
|
|
60
|
+
- `worktreePath` — absolute path to the worktree, if this workspace is a worktree
|
|
60
61
|
- `workspaceRoot` — absolute path to the code workspace
|
|
61
|
-
- `sessionId` — real agent-runtime session id (never a synthesized UUID)
|
|
62
|
+
- `sessionId` — real agent-runtime session id (legacy hint; never a synthesized UUID, and a co-tenant can clobber it — not authoritative for identity)
|
|
62
63
|
- `transcriptPath` — absolute path to the agent's rollout/transcript file, if known
|
|
63
64
|
- `leases` — array of active resource-lease records (managed by `/claim-resource` and `/release-resource`). Entry shape: `{ lease_id, inventory_slug, member_id, expires_at, metadata, claimed_at }`. Leases are NOT auto-released on session end or assignment completion in v1 — call `/release-resource` explicitly (or let the TTL expire).
|
|
65
|
+
- `bundleId` and related bundle fields — present when this workspace is bound to a todo bundle (managed by the bundle skills).
|
|
64
66
|
|
|
65
67
|
## Required Reading Order
|
|
66
68
|
|
|
@@ -64,4 +64,4 @@ When working on code (not protocol files), you may write to files within the wor
|
|
|
64
64
|
|
|
65
65
|
- `workspace.worktreePath` or `workspace.repository` defines your code root.
|
|
66
66
|
- You may create and edit source files within that workspace.
|
|
67
|
-
- The `.syntaur/context.json`
|
|
67
|
+
- The `.syntaur/context.json` workspace-marker file in your working directory is also writable (merge, don't overwrite — the platform SessionStart hook may have populated `sessionId` and `transcriptPath`). It marks the workspace (repository/branch/worktree); it is not the active-assignment source of truth — the active assignment resolves from the session's open engagement.
|
|
@@ -23,8 +23,9 @@ operations:
|
|
|
23
23
|
transactionally — rolls back the worktree on write failure).
|
|
24
24
|
3. `syntaur assign` + `syntaur start` — claim the assignment for this agent
|
|
25
25
|
and transition to `in_progress`.
|
|
26
|
-
4. Write `.syntaur/context.json` inside the new worktree
|
|
27
|
-
|
|
26
|
+
4. Write `.syntaur/context.json` (a workspace marker) inside the new worktree,
|
|
27
|
+
then `syntaur track-session` to bind the session's engagement to the
|
|
28
|
+
assignment.
|
|
28
29
|
|
|
29
30
|
## When NOT to use this skill
|
|
30
31
|
|
|
@@ -82,12 +83,15 @@ syntaur start <assignment> --project <project-slug> # only if status was pendi
|
|
|
82
83
|
Skip `start` for any non-`pending` status — never rewind a `review`,
|
|
83
84
|
`completed`, or `failed` assignment.
|
|
84
85
|
|
|
85
|
-
## Step 5:
|
|
86
|
+
## Step 5: Write the workspace marker
|
|
86
87
|
|
|
87
|
-
`cd` into the new worktree path. Write
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
`cd` into the new worktree path. Write `<worktreePath>/.syntaur/context.json`
|
|
89
|
+
mirroring the WORKSPACE-MARKER format produced by `/grab-assignment`:
|
|
90
|
+
`repository`, `branch`, `worktreePath`, `workspaceRoot`, `grabbedAt`, plus
|
|
91
|
+
`sessionId` / `transcriptPath` when known. Do NOT write `projectSlug` /
|
|
92
|
+
`assignmentSlug` / `assignmentDir` / `projectDir` / `title` — context.json is a
|
|
93
|
+
workspace marker, not the active-assignment source. The assignment binds in the
|
|
94
|
+
next step via the session's engagement (`track-session`).
|
|
91
95
|
|
|
92
96
|
If the runtime exposes a real session id (e.g. Claude Code's
|
|
93
97
|
`~/.claude/sessions/`), include it. Otherwise omit `sessionId` entirely; the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "syntaur",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"description": "Run Syntaur project and assignment workflows from Codex, including claiming work, planning, completing handoffs, session/server tracking, save-session-summary continuity, and write-boundary enforcement.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Brennen"
|
|
@@ -45,39 +45,97 @@ if [ -z "$FILE_PATH" ]; then
|
|
|
45
45
|
allow_and_exit
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
|
+
# context.json is a WORKSPACE MARKER. Its presence means "Syntaur-enforced
|
|
49
|
+
# workspace"; its absence means "not a Syntaur workspace → allow".
|
|
48
50
|
CONTEXT_FILE=".syntaur/context.json"
|
|
49
51
|
if [ ! -f "$CONTEXT_FILE" ]; then
|
|
50
52
|
allow_and_exit
|
|
51
53
|
fi
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
# Resolve the write boundary from the session's OPEN engagement (the assignment
|
|
56
|
+
# scalars were demoted out of context.json). Codex's PreToolUse stdin MAY carry
|
|
57
|
+
# .session_id; if absent, fall back to the ancestor-pid runtime markers (same
|
|
58
|
+
# scheme as session-cleanup.sh). Pass whatever id we have to the CLI explicitly.
|
|
59
|
+
# If the CLI is unavailable or resolves nothing, ASSIGNMENT_DIR/MISSION_DIR stay
|
|
60
|
+
# empty → WORKSPACE-ONLY enforcement below (NOT fail-open).
|
|
61
|
+
ASSIGNMENT_DIR=""
|
|
62
|
+
MISSION_DIR=""
|
|
63
|
+
WORKSPACE_ROOT=""
|
|
64
|
+
|
|
65
|
+
CONTEXT_DIR="$(cd "$(dirname "$CONTEXT_FILE")/.." 2>/dev/null && pwd)"
|
|
66
|
+
[ -z "$CONTEXT_DIR" ] && CONTEXT_DIR="$(pwd)"
|
|
67
|
+
|
|
68
|
+
SID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
69
|
+
if [ -z "$SID" ]; then
|
|
70
|
+
# Fall back to ancestor-pid runtime markers (pid-reuse-guarded by procStart).
|
|
71
|
+
RUNTIME_DIR="${SYNTAUR_RUNTIME_SESSIONS_DIR:-$HOME/.syntaur/runtime/sessions}"
|
|
72
|
+
_pid="$PPID"
|
|
73
|
+
_depth=0
|
|
74
|
+
while [ "$_depth" -lt 12 ]; do
|
|
75
|
+
case "$_pid" in
|
|
76
|
+
'' | *[!0-9]*) break ;;
|
|
77
|
+
esac
|
|
78
|
+
[ "$_pid" -le 1 ] && break
|
|
79
|
+
_marker="$RUNTIME_DIR/$_pid.json"
|
|
80
|
+
if [ -f "$_marker" ]; then
|
|
81
|
+
_sid=$(jq -r '.sessionId // empty' "$_marker" 2>/dev/null)
|
|
82
|
+
_procstart=$(jq -r '.procStart // empty' "$_marker" 2>/dev/null)
|
|
83
|
+
if [ -n "$_sid" ]; then
|
|
84
|
+
if [ -n "$_procstart" ]; then
|
|
85
|
+
_actual=$(ps -o lstart= -p "$_pid" 2>/dev/null | sed 's/^ *//;s/ *$//')
|
|
86
|
+
if [ -n "$_actual" ] && [ "$_actual" = "$_procstart" ]; then
|
|
87
|
+
SID="$_sid"
|
|
88
|
+
break
|
|
89
|
+
fi
|
|
90
|
+
else
|
|
91
|
+
SID="$_sid"
|
|
92
|
+
break
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
fi
|
|
96
|
+
_pid=$(ps -o ppid= -p "$_pid" 2>/dev/null | tr -d ' ')
|
|
97
|
+
_depth=$((_depth + 1))
|
|
98
|
+
done
|
|
99
|
+
fi
|
|
56
100
|
|
|
57
|
-
if
|
|
58
|
-
|
|
101
|
+
if command -v syntaur >/dev/null 2>&1; then
|
|
102
|
+
BOUNDARY_JSON=$(cd "$CONTEXT_DIR" 2>/dev/null && \
|
|
103
|
+
syntaur session boundary --json ${SID:+--session-id "$SID"} 2>/dev/null)
|
|
104
|
+
if [ -n "$BOUNDARY_JSON" ]; then
|
|
105
|
+
ASSIGNMENT_DIR=$(echo "$BOUNDARY_JSON" | jq -r '.assignmentDir // empty' 2>/dev/null)
|
|
106
|
+
MISSION_DIR=$(echo "$BOUNDARY_JSON" | jq -r '.projectDir // empty' 2>/dev/null)
|
|
107
|
+
WORKSPACE_ROOT=$(echo "$BOUNDARY_JSON" | jq -r '.workspaceRoot // empty' 2>/dev/null)
|
|
108
|
+
fi
|
|
59
109
|
fi
|
|
60
110
|
|
|
61
|
-
|
|
62
|
-
|
|
111
|
+
# Fall back to the context.json workspace marker if the CLI did not surface one.
|
|
112
|
+
if [ -z "$WORKSPACE_ROOT" ]; then
|
|
113
|
+
WORKSPACE_ROOT=$(jq -r '.workspaceRoot // empty' "$CONTEXT_FILE" 2>/dev/null)
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
[ -n "$ASSIGNMENT_DIR" ] && ASSIGNMENT_DIR="${ASSIGNMENT_DIR/#\~/$HOME}"
|
|
117
|
+
[ -n "$MISSION_DIR" ] && MISSION_DIR="${MISSION_DIR/#\~/$HOME}"
|
|
63
118
|
if [ -n "$WORKSPACE_ROOT" ] && [ "$WORKSPACE_ROOT" != "null" ]; then
|
|
64
119
|
WORKSPACE_ROOT="${WORKSPACE_ROOT/#\~/$HOME}"
|
|
65
120
|
else
|
|
66
121
|
WORKSPACE_ROOT=""
|
|
67
122
|
fi
|
|
68
123
|
|
|
69
|
-
|
|
124
|
+
# Every prefix test is guarded so an EMPTY $DIR never globs to "/*" and allows
|
|
125
|
+
# the whole filesystem. No assignment → only workspace-root/context match →
|
|
126
|
+
# WORKSPACE-ONLY enforcement (NOT fail-open).
|
|
127
|
+
if [ -n "$ASSIGNMENT_DIR" ] && [[ "$FILE_PATH" == "$ASSIGNMENT_DIR"/* ]]; then
|
|
70
128
|
allow_and_exit
|
|
71
129
|
fi
|
|
72
130
|
|
|
73
|
-
if [[ "$FILE_PATH" == "$MISSION_DIR/resources/"* ]]; then
|
|
131
|
+
if [ -n "$MISSION_DIR" ] && [[ "$FILE_PATH" == "$MISSION_DIR/resources/"* ]]; then
|
|
74
132
|
BASENAME=$(basename "$FILE_PATH")
|
|
75
133
|
if [[ "$BASENAME" != _* ]]; then
|
|
76
134
|
allow_and_exit
|
|
77
135
|
fi
|
|
78
136
|
fi
|
|
79
137
|
|
|
80
|
-
if [[ "$FILE_PATH" == "$MISSION_DIR/memories/"* ]]; then
|
|
138
|
+
if [ -n "$MISSION_DIR" ] && [[ "$FILE_PATH" == "$MISSION_DIR/memories/"* ]]; then
|
|
81
139
|
BASENAME=$(basename "$FILE_PATH")
|
|
82
140
|
if [[ "$BASENAME" != _* ]]; then
|
|
83
141
|
allow_and_exit
|
|
@@ -85,7 +143,7 @@ if [[ "$FILE_PATH" == "$MISSION_DIR/memories/"* ]]; then
|
|
|
85
143
|
fi
|
|
86
144
|
|
|
87
145
|
CONTEXT_ABS="$(cd "$(dirname "$CONTEXT_FILE")" 2>/dev/null && echo "$(pwd)/$(basename "$CONTEXT_FILE")")"
|
|
88
|
-
if [ "$FILE_PATH" = "$CONTEXT_ABS" ]; then
|
|
146
|
+
if [ -n "$CONTEXT_ABS" ] && [ "$FILE_PATH" = "$CONTEXT_ABS" ]; then
|
|
89
147
|
allow_and_exit
|
|
90
148
|
fi
|
|
91
149
|
|
|
@@ -93,7 +151,11 @@ if [ -n "$WORKSPACE_ROOT" ] && [[ "$FILE_PATH" == "$WORKSPACE_ROOT"/* ]]; then
|
|
|
93
151
|
allow_and_exit
|
|
94
152
|
fi
|
|
95
153
|
|
|
96
|
-
|
|
154
|
+
if [ -n "$ASSIGNMENT_DIR" ]; then
|
|
155
|
+
REASON="Syntaur write boundary violation: Cannot write to '$FILE_PATH'. Allowed paths: assignment dir ($ASSIGNMENT_DIR), project resources/memories${MISSION_DIR:+ ($MISSION_DIR)}, workspace (${WORKSPACE_ROOT:-none})."
|
|
156
|
+
else
|
|
157
|
+
REASON="Syntaur write boundary violation: Cannot write to '$FILE_PATH'. No active assignment for this session — writes are restricted to the workspace (${WORKSPACE_ROOT:-none})."
|
|
158
|
+
fi
|
|
97
159
|
REASON_ESCAPED=$(echo "$REASON" | jq -Rs '.' 2>/dev/null)
|
|
98
160
|
if [ -z "$REASON_ESCAPED" ]; then
|
|
99
161
|
REASON_ESCAPED="\"Syntaur write boundary violation\""
|
|
@@ -31,19 +31,6 @@ if [ ! -f "$CONTEXT_FILE" ]; then
|
|
|
31
31
|
exit 0
|
|
32
32
|
fi
|
|
33
33
|
|
|
34
|
-
# Keep derived status fresh on session end — CLI-direct (NO dashboard
|
|
35
|
-
# dependency, unlike the session-stop PATCH below), migration-gated, and bounded
|
|
36
|
-
# (~3s; no `timeout` on stock macOS). Best-effort; never blocks teardown.
|
|
37
|
-
if command -v syntaur >/dev/null 2>&1; then
|
|
38
|
-
( cd "$CWD" 2>/dev/null && syntaur recompute --if-migrated >/dev/null 2>&1 ) &
|
|
39
|
-
syntaur_rc_pid=$!
|
|
40
|
-
( sleep 3; kill -KILL "$syntaur_rc_pid" 2>/dev/null ) >/dev/null 2>&1 &
|
|
41
|
-
syntaur_rc_killer=$!
|
|
42
|
-
wait "$syntaur_rc_pid" 2>/dev/null || true
|
|
43
|
-
kill -KILL "$syntaur_rc_killer" 2>/dev/null
|
|
44
|
-
wait "$syntaur_rc_killer" 2>/dev/null || true
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
34
|
RUNTIME_DIR="${SYNTAUR_RUNTIME_SESSIONS_DIR:-$HOME/.syntaur/runtime/sessions}"
|
|
48
35
|
|
|
49
36
|
# Walk the ancestor-pid chain reading runtime markers. Returns the nearest
|
|
@@ -84,6 +71,26 @@ resolve_session_from_markers() {
|
|
|
84
71
|
}
|
|
85
72
|
|
|
86
73
|
SESSION_ID=$(resolve_session_from_markers || true)
|
|
74
|
+
|
|
75
|
+
# Keep derived status fresh on session end — keyed on the ending session's EXACT
|
|
76
|
+
# id (the marker-resolved id, else the stdin id for runtimes that provide one).
|
|
77
|
+
# Skip when NEITHER resolves, rather than fall back to ambiguous cwd own-session
|
|
78
|
+
# resolution that could recompute the WRONG assignment in a shared worktree.
|
|
79
|
+
# Runs BEFORE the stop PATCH below, so the engagement is still open. CLI-direct
|
|
80
|
+
# (no dashboard), migration-gated, bounded (~3s; no `timeout` on stock macOS).
|
|
81
|
+
STDIN_SID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
82
|
+
RECOMPUTE_SID="${SESSION_ID:-$STDIN_SID}"
|
|
83
|
+
if [ -n "$RECOMPUTE_SID" ] && command -v syntaur >/dev/null 2>&1; then
|
|
84
|
+
( cd "$CWD" 2>/dev/null && \
|
|
85
|
+
syntaur recompute --if-migrated --session-id "$RECOMPUTE_SID" >/dev/null 2>&1 ) &
|
|
86
|
+
syntaur_rc_pid=$!
|
|
87
|
+
( sleep 3; kill -KILL "$syntaur_rc_pid" 2>/dev/null ) >/dev/null 2>&1 &
|
|
88
|
+
syntaur_rc_killer=$!
|
|
89
|
+
wait "$syntaur_rc_pid" 2>/dev/null || true
|
|
90
|
+
kill -KILL "$syntaur_rc_killer" 2>/dev/null
|
|
91
|
+
wait "$syntaur_rc_killer" 2>/dev/null || true
|
|
92
|
+
fi
|
|
93
|
+
|
|
87
94
|
MISSION_SLUG=$(jq -r '.projectSlug // empty' "$CONTEXT_FILE" 2>/dev/null)
|
|
88
95
|
|
|
89
96
|
# No EXACT id — do not risk stopping the wrong co-tenant session.
|
|
@@ -32,8 +32,9 @@ file-ownership protocol.
|
|
|
32
32
|
|
|
33
33
|
## Step 1: Resolve project
|
|
34
34
|
|
|
35
|
-
If
|
|
36
|
-
|
|
35
|
+
If the session has an open engagement with an active assignment (`syntaur
|
|
36
|
+
session resume --json`), default to its `projectSlug`. Otherwise ask the user
|
|
37
|
+
which project to add the memory to.
|
|
37
38
|
|
|
38
39
|
## Step 2: Gather inputs
|
|
39
40
|
|
|
@@ -30,8 +30,9 @@ CLI-managed file per the file-ownership protocol).
|
|
|
30
30
|
|
|
31
31
|
## Step 1: Resolve project
|
|
32
32
|
|
|
33
|
-
If
|
|
34
|
-
|
|
33
|
+
If the session has an open engagement with an active assignment (`syntaur
|
|
34
|
+
session resume --json`), default to its `projectSlug`. Otherwise ask the user
|
|
35
|
+
which project to add the resource to.
|
|
35
36
|
|
|
36
37
|
## Step 2: Gather inputs
|
|
37
38
|
|
|
@@ -45,9 +45,9 @@ The computed worktree path is **always**
|
|
|
45
45
|
|
|
46
46
|
## Step 2: Pre-flight
|
|
47
47
|
|
|
48
|
-
- Confirm `.syntaur/context.json` is a bundle context (has `bundleId
|
|
49
|
-
|
|
50
|
-
user to `/grab-bundle <id>` first.
|
|
48
|
+
- Confirm `.syntaur/context.json` is a bundle context (has `bundleId`). If the
|
|
49
|
+
session is instead bound to an assignment (an open engagement) with no
|
|
50
|
+
`bundleId`, stop and tell the user to `/grab-bundle <id>` first.
|
|
51
51
|
- Confirm `<repository>/.git` exists.
|
|
52
52
|
- Confirm the branch does NOT already exist. If it does, the CLI will
|
|
53
53
|
surface a `GitWorktreeError` — surface that verbatim.
|
|
@@ -17,7 +17,7 @@ Attach proof to your work. Reviewers should be able to scroll a single page (`pr
|
|
|
17
17
|
|
|
18
18
|
## Input
|
|
19
19
|
|
|
20
|
-
No arguments.
|
|
20
|
+
No arguments. The active assignment is resolved from the session's open engagement (`.syntaur/context.json` is only a workspace marker, not the assignment source).
|
|
21
21
|
|
|
22
22
|
## Step 1: Decide whether to capture
|
|
23
23
|
|
|
@@ -60,7 +60,7 @@ Rules:
|
|
|
60
60
|
- All other kinds (`screenshot`, `video`, `asciinema`) require `--file`. The CLI rejects nonexistent / non-file paths.
|
|
61
61
|
- `--criterion <index>` is optional — pass the **0-based** index into the `## Acceptance Criteria` checklist when you want to anchor the artifact to a specific criterion.
|
|
62
62
|
- `--transcribe` is video-only and writes a sibling `<id>.transcript.md` (requires `ELEVENLABS_API_KEY` + `ffmpeg`). `proof build` renders the transcript next to the player; clicking a phrase seeks the video.
|
|
63
|
-
- If
|
|
63
|
+
- If this session has an open engagement (active assignment), the positional target argument is unnecessary — the CLI resolves the target from the engagement. Otherwise pass `--project <slug> <assignment-slug>` or a bare assignment UUID.
|
|
64
64
|
|
|
65
65
|
The CLI copies the file (if any) under `<assignmentDir>/proof/<criterion|untagged>/<id>.<ext>` and inserts a row in `~/.syntaur/syntaur.db`. Output prints the artifact id and absolute path.
|
|
66
66
|
|
|
@@ -29,15 +29,15 @@ Examples:
|
|
|
29
29
|
|
|
30
30
|
Extract `<inventory_slug>` (required, first positional), plus optional `--ttl <duration>` and `--for <tag>`.
|
|
31
31
|
|
|
32
|
-
### Step 2: Pre-check
|
|
32
|
+
### Step 2: Pre-check workspace context
|
|
33
33
|
|
|
34
|
-
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR
|
|
34
|
+
Read `.syntaur/context.json` (a workspace marker) from the current working directory. If the file is missing, OR carries no workspace markers (`repository`/`branch`/`worktreePath`/`workspaceRoot`) and no `sessionId`, abort with:
|
|
35
35
|
|
|
36
36
|
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
37
37
|
|
|
38
38
|
This guard exists because writing a leases-only context file would trip `syntaur doctor`'s workspace check.
|
|
39
39
|
|
|
40
|
-
If `--for` was not provided, derive its value from the
|
|
40
|
+
If `--for` was not provided, derive its value: prefer the active assignment's slug from the session's open engagement (`syntaur session resume --json`); otherwise fall back to the `sessionId` from the workspace marker.
|
|
41
41
|
|
|
42
42
|
### Step 3: Run the claim CLI
|
|
43
43
|
|
|
@@ -14,7 +14,7 @@ metadata:
|
|
|
14
14
|
|
|
15
15
|
# Clear Assignment
|
|
16
16
|
|
|
17
|
-
Drop the active assignment binding from the current
|
|
17
|
+
Drop the active assignment binding from the current session. The assignment itself is left untouched in `~/.syntaur/projects/.../assignments/` — only the session's open engagement (the binding that makes it the active assignment) is closed so the session is no longer scoped to it. `.syntaur/context.json` is a workspace marker and is not the binding — it does not hold the active assignment.
|
|
18
18
|
|
|
19
19
|
This is the inverse of `grab-assignment`. Unlike `complete-assignment`, it does **not** transition lifecycle state, write a handoff, or close out the work. Use it when:
|
|
20
20
|
|
|
@@ -28,17 +28,15 @@ If the assignment is actually done, use `complete-assignment` instead so a hando
|
|
|
28
28
|
|
|
29
29
|
Optional flags from the user:
|
|
30
30
|
|
|
31
|
-
- `--
|
|
32
|
-
- `--unassign` — also run `syntaur unassign <slug> --project <project>` so the assignment is no longer claimed by this agent. Default: leave the claim in place (only the local context is cleared).
|
|
31
|
+
- `--unassign` — also run `syntaur unassign <slug> --project <project>` so the assignment is no longer claimed by this agent. Default: leave the claim in place (only the session's engagement is closed).
|
|
33
32
|
|
|
34
33
|
## Step 1: Load Context
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
The active assignment is resolved from the session's open engagement. Run `syntaur session resume --json` to read it.
|
|
37
36
|
|
|
38
|
-
- If
|
|
39
|
-
- If the file exists but contains only session fields (`sessionId`, `transcriptPath`) and no `projectSlug` / `assignmentSlug`, tell the user: "No active assignment is bound — only a platform session record exists. Nothing to clear." and stop (unless they explicitly ask to wipe the session record too).
|
|
37
|
+
- If there is no open engagement, tell the user: "No active assignment is bound to this session — nothing to clear." and stop. (`.syntaur/context.json` is only a workspace marker; its presence does not mean an assignment is bound.)
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
From the resolved engagement, note: `projectSlug`, `assignmentSlug`, `assignmentDir`, `title`.
|
|
42
40
|
|
|
43
41
|
## Step 2: Confirm with the User
|
|
44
42
|
|
|
@@ -68,29 +66,15 @@ For standalone assignments use the UUID (the folder name) in place of the slug,
|
|
|
68
66
|
|
|
69
67
|
`syntaur unassign` clears the assignee on the assignment frontmatter (the inverse of `assign`) and bumps `updated`.
|
|
70
68
|
|
|
71
|
-
## Step 4:
|
|
69
|
+
## Step 4: Close the Engagement
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
Closing the session's open engagement is what drops the active-assignment binding — that is the operation that "clears" the assignment. The dashboard status PATCH in Step 5 (to `cleared`) closes the open engagement for a live session.
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
rm .syntaur/context.json
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
If the user passed `--keep-session`, preserve session fields and strip everything else instead:
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
jq '{sessionId, transcriptPath} | with_entries(select(.value != null))' \
|
|
83
|
-
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
84
|
-
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
If the resulting file would be empty (`{}`), delete it instead of leaving an empty stub.
|
|
88
|
-
|
|
89
|
-
Do not delete the `.syntaur/` directory itself — other tooling may use it.
|
|
73
|
+
Do NOT delete or rewrite `.syntaur/context.json` to clear the assignment — it is a workspace marker and no longer carries the active assignment. Leave its repository/branch/worktree, session, and lease fields intact so other tooling keeps recognizing the workspace. Do not delete the `.syntaur/` directory.
|
|
90
74
|
|
|
91
75
|
## Step 5: Close Session (optional)
|
|
92
76
|
|
|
93
|
-
If the Syntaur dashboard is running, mark this session as cleared so the dashboard does not keep showing it as active. Resolve `<session-id>` from *your* running process — prefer `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`), otherwise run `syntaur session resolve-id`. Only if neither yields an id, fall back to the `sessionId`
|
|
77
|
+
If the Syntaur dashboard is running, mark this session as cleared so the dashboard does not keep showing it as active (this also closes the session's open engagement). Resolve `<session-id>` from *your* running process — prefer `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`), otherwise run `syntaur session resolve-id`. Only if neither yields an id, fall back to the legacy `sessionId` scalar in `.syntaur/context.json` — that scalar is a shared, legacy hint a co-tenant can clobber, so don't treat it as authoritative:
|
|
94
78
|
|
|
95
79
|
```bash
|
|
96
80
|
curl -s -X PATCH "http://localhost:$(cat ~/.syntaur/dashboard-port 2>/dev/null || echo 4800)/api/agent-sessions/<session-id>/status" \
|
|
@@ -100,8 +84,6 @@ curl -s -X PATCH "http://localhost:$(cat ~/.syntaur/dashboard-port 2>/dev/null |
|
|
|
100
84
|
|
|
101
85
|
If this fails (e.g., dashboard not running, endpoint not present in the installed version), it is non-critical — silently continue.
|
|
102
86
|
|
|
103
|
-
Skip this step entirely when `--keep-session` is set.
|
|
104
|
-
|
|
105
87
|
## Step 6: Report to User
|
|
106
88
|
|
|
107
89
|
Summarize:
|
|
@@ -19,11 +19,11 @@ Optional: the user may pass `--complete` to transition directly to `completed` i
|
|
|
19
19
|
|
|
20
20
|
## Step 1: Load Context
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The active assignment is resolved from the session's open engagement. Run `syntaur session resume --json` to read it.
|
|
23
23
|
|
|
24
|
-
If
|
|
24
|
+
If there is no open engagement (no active assignment), tell the user: "No active assignment for this session — grab one first." `.syntaur/context.json` is only a workspace marker; do not read the assignment from it.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
From the resolved engagement, note: `projectSlug`, `assignmentSlug`, `assignmentDir`, `projectDir`.
|
|
27
27
|
|
|
28
28
|
## Step 2: Load Playbooks
|
|
29
29
|
|
|
@@ -30,9 +30,9 @@ Expects arguments from the user:
|
|
|
30
30
|
|
|
31
31
|
If no title was provided, ask the user what the assignment should be called.
|
|
32
32
|
|
|
33
|
-
If neither `--project` nor `--one-off` was provided, check
|
|
33
|
+
If neither `--project` nor `--one-off` was provided, check for an active assignment via the session's open engagement (`syntaur session resume --json`). If there is one, default `--project` to its `projectSlug` and confirm with the user: "Add this assignment to project `<projectSlug>`?"
|
|
34
34
|
|
|
35
|
-
If no
|
|
35
|
+
If there is no open engagement and no project flag, ask the user which project to add it to, or whether it should be a one-off.
|
|
36
36
|
|
|
37
37
|
## Step 1: Run the CLI
|
|
38
38
|
|
|
@@ -25,9 +25,9 @@ Examples:
|
|
|
25
25
|
|
|
26
26
|
Extract `<lease_id>` (first positional) and `--ttl <duration>` (required). If either is missing, abort with a usage message and a hint to call `/list-resources` to see active leases.
|
|
27
27
|
|
|
28
|
-
### Step 2: Pre-check
|
|
28
|
+
### Step 2: Pre-check workspace context
|
|
29
29
|
|
|
30
|
-
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR
|
|
30
|
+
Read `.syntaur/context.json` (a workspace marker) from the current working directory. If the file is missing, OR carries no workspace markers (`repository`/`branch`/`worktreePath`/`workspaceRoot`) and no `sessionId`, abort with:
|
|
31
31
|
|
|
32
32
|
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
33
33
|
|
|
@@ -23,10 +23,16 @@ Expects up to two arguments from the user:
|
|
|
23
23
|
|
|
24
24
|
## Pre-flight Check
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
`.syntaur/context.json` is a WORKSPACE MARKER (repository/branch/worktree/workspaceRoot plus legacy session and bundle fields) — it is NOT the active-assignment source of truth. The active assignment binds via the session's open engagement (established by `track-session` in Step 6).
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Check whether this session already has an open engagement — i.e., a different assignment is already active:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
syntaur session resume --json 2>/dev/null
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- If it reports an active assignment, warn the user: "You already have an active assignment: `<assignmentSlug>` in project `<projectSlug>`. Grabbing a new one will rebind this session. Proceed?" — stop if the user says no.
|
|
35
|
+
- If there is no open engagement (no active assignment), proceed. A `.syntaur/context.json` that holds only workspace-marker / session fields is expected — it does not represent an active assignment.
|
|
30
36
|
|
|
31
37
|
## Step 1: Discover the Project (project-nested path)
|
|
32
38
|
|
|
@@ -75,25 +81,24 @@ From the assignment frontmatter extract: `title`, `workspace.repository`, `works
|
|
|
75
81
|
|
|
76
82
|
If `workspace.repository` and `workspace.worktreePath` are both null, set them to the current working directory. Write boundaries use this path, so it must never be null while an agent is writing code.
|
|
77
83
|
|
|
78
|
-
## Step 5: Create or Merge
|
|
84
|
+
## Step 5: Create or Merge the Workspace Marker
|
|
79
85
|
|
|
80
|
-
|
|
86
|
+
`.syntaur/context.json` is a WORKSPACE MARKER — it records the repository/branch/worktree so tooling can recognize this directory as a Syntaur workspace. It is NOT the active-assignment source of truth: the assignment binds via the session's open engagement (Step 6, `track-session`). Do NOT write `projectSlug` / `assignmentSlug` / `assignmentDir` / `projectDir` / `title` — those scalars are non-authoritative.
|
|
87
|
+
|
|
88
|
+
Merge workspace markers into `.syntaur/context.json`. Never overwrite — if the file already exists (e.g., platform SessionStart hook populated `sessionId` / `transcriptPath`, or a worktree skill wrote bundle/lease fields), preserve those fields.
|
|
81
89
|
|
|
82
90
|
```bash
|
|
83
91
|
mkdir -p .syntaur
|
|
84
92
|
```
|
|
85
93
|
|
|
86
|
-
Prepare the
|
|
94
|
+
Prepare the workspace-marker payload:
|
|
87
95
|
|
|
88
96
|
```json
|
|
89
97
|
{
|
|
90
|
-
"
|
|
91
|
-
"assignmentSlug": "<assignment-slug>",
|
|
92
|
-
"projectDir": "/absolute/path/to/project or null",
|
|
93
|
-
"assignmentDir": "/absolute/path/to/assignment",
|
|
94
|
-
"workspaceRoot": "<workspace path or current working directory>",
|
|
95
|
-
"title": "<assignment title>",
|
|
98
|
+
"repository": "<workspace.repository or null>",
|
|
96
99
|
"branch": "<workspace.branch or null>",
|
|
100
|
+
"worktreePath": "<workspace.worktreePath or null>",
|
|
101
|
+
"workspaceRoot": "<workspace path or current working directory>",
|
|
97
102
|
"grabbedAt": "<ISO 8601 timestamp>"
|
|
98
103
|
}
|
|
99
104
|
```
|
|
@@ -34,16 +34,20 @@ the user to pick.
|
|
|
34
34
|
|
|
35
35
|
## Pre-flight check
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
First check whether this session already has an active assignment via its open
|
|
38
|
+
engagement (`syntaur session resume --json`):
|
|
39
|
+
|
|
40
|
+
- If it reports an active assignment, warn the user: "You already have an active
|
|
41
|
+
assignment. Grabbing a bundle will rebind this session. Proceed?" — stop if no.
|
|
42
|
+
|
|
43
|
+
Then read `.syntaur/context.json` (a workspace marker) in the current working
|
|
44
|
+
directory for bundle bookkeeping:
|
|
38
45
|
|
|
39
|
-
- If it already contains assignment fields (`projectSlug`/`assignmentSlug`/
|
|
40
|
-
`assignmentDir`), warn the user: "You already have an active assignment.
|
|
41
|
-
Grabbing a bundle will replace this context. Proceed?" — stop if no.
|
|
42
46
|
- If it already contains different bundle fields (`bundleId` set to a
|
|
43
47
|
different id), warn: "Context is bound to bundle b:<old>. Switch to b:<new>?"
|
|
44
48
|
— stop if no.
|
|
45
|
-
-
|
|
46
|
-
and merge bundle fields on top.
|
|
49
|
+
- A context.json holding only workspace-marker / `sessionId` fields is expected;
|
|
50
|
+
proceed and merge bundle fields on top.
|
|
47
51
|
|
|
48
52
|
## Step 1: Load the bundle
|
|
49
53
|
|
|
@@ -39,9 +39,11 @@ records current in real-time, especially after every meaningful action.
|
|
|
39
39
|
|
|
40
40
|
## Step 1: Verify there is an active assignment
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
42
|
+
The active assignment is resolved from the session's open engagement — `syntaur
|
|
43
|
+
progress log` (Step 3) targets it automatically. `.syntaur/context.json` is only
|
|
44
|
+
a workspace marker; do not read the assignment from it. If there is no open
|
|
45
|
+
engagement (no active assignment), the CLI aborts with "No active assignment for
|
|
46
|
+
this session — grab one first." Run `grab-assignment` first.
|
|
45
47
|
|
|
46
48
|
## Step 2: Compose the entry
|
|
47
49
|
|
|
@@ -69,7 +71,7 @@ Run:
|
|
|
69
71
|
syntaur progress log "<your composed entry body>"
|
|
70
72
|
```
|
|
71
73
|
|
|
72
|
-
The command resolves the active assignment from
|
|
74
|
+
The command resolves the active assignment from the session's open engagement
|
|
73
75
|
(or pass `--assignment <slug> [--project <slug>]` to target one explicitly),
|
|
74
76
|
then atomically:
|
|
75
77
|
|
|
@@ -20,14 +20,14 @@ Optional: the user may provide focus areas or notes to guide the plan.
|
|
|
20
20
|
|
|
21
21
|
## Step 1: Load Context
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
The active assignment is resolved from the session's open engagement. Run `syntaur session resume --json` to read it. If there is no open engagement (no active assignment), tell the user: "No active assignment for this session — grab one first." and stop. `.syntaur/context.json` is only a workspace marker; do not read the assignment from it.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
From the resolved engagement, note:
|
|
26
26
|
- `projectSlug` — the project slug (`null` for standalone assignments)
|
|
27
27
|
- `assignmentSlug` — the assignment slug
|
|
28
28
|
- `assignmentDir` — absolute path to the assignment folder
|
|
29
29
|
- `projectDir` — absolute path to the project folder (may be null for standalone)
|
|
30
|
-
- `workspaceRoot` — absolute path to the workspace (may be null)
|
|
30
|
+
- `workspaceRoot` — absolute path to the workspace (a workspace marker; may be null)
|
|
31
31
|
|
|
32
32
|
## Step 2: Load Playbooks
|
|
33
33
|
|
|
@@ -19,9 +19,10 @@ the bundle's own to track, only the member todos.
|
|
|
19
19
|
|
|
20
20
|
## Step 1: Load context
|
|
21
21
|
|
|
22
|
-
Read `.syntaur/context.json` from the current working
|
|
23
|
-
contain `bundleId` (a bundle context). If
|
|
24
|
-
|
|
22
|
+
Read `.syntaur/context.json` (a workspace marker) from the current working
|
|
23
|
+
directory. It must contain `bundleId` (a bundle context). If there is no
|
|
24
|
+
`bundleId` but the session has an open engagement (an active assignment), stop
|
|
25
|
+
and tell the user: "This session is bound to an assignment, not a bundle.
|
|
25
26
|
Use `/plan-assignment` instead, or `/grab-bundle <id>` to switch."
|
|
26
27
|
|
|
27
28
|
Extract `bundleId`, `bundleScope`, `bundleScopeId`, `todoIds`, `planDir`.
|