syntaur 0.3.0 → 0.4.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/README.md +26 -3
- package/dist/dashboard/server.js +497 -315
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +1240 -550
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/claude-code/agents/syntaur-expert.md +35 -20
- package/platforms/claude-code/commands/complete-assignment/complete-assignment.md +20 -0
- package/platforms/claude-code/commands/create-assignment/create-assignment.md +20 -0
- package/platforms/claude-code/commands/create-project/create-project.md +20 -0
- package/platforms/claude-code/commands/grab-assignment/grab-assignment.md +20 -0
- package/platforms/claude-code/commands/plan-assignment/plan-assignment.md +20 -0
- package/platforms/claude-code/commands/track-session/track-session.md +43 -18
- package/platforms/claude-code/hooks/hooks.json +11 -0
- package/platforms/claude-code/hooks/session-cleanup.sh +13 -23
- package/platforms/claude-code/hooks/session-start.sh +80 -0
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/codex/agents/syntaur-operator.md +6 -4
- package/platforms/codex/scripts/resolve-session.sh +49 -0
- package/statusline/statusline.sh +133 -0
- package/vendor/syntaur-skills/LICENSE +21 -0
- package/vendor/syntaur-skills/README.md +43 -0
- package/vendor/syntaur-skills/skills/complete-assignment/SKILL.md +146 -0
- package/vendor/syntaur-skills/skills/create-assignment/SKILL.md +72 -0
- package/vendor/syntaur-skills/skills/create-project/SKILL.md +56 -0
- package/vendor/syntaur-skills/skills/grab-assignment/SKILL.md +158 -0
- package/vendor/syntaur-skills/skills/plan-assignment/SKILL.md +137 -0
- package/vendor/syntaur-skills/skills/syntaur-protocol/SKILL.md +119 -0
- package/vendor/syntaur-skills/skills/syntaur-protocol/references/file-ownership.md +67 -0
- package/vendor/syntaur-skills/skills/syntaur-protocol/references/protocol-summary.md +82 -0
- package/platforms/claude-code/skills/complete-assignment/SKILL.md +0 -155
- package/platforms/claude-code/skills/create-assignment/SKILL.md +0 -67
- package/platforms/claude-code/skills/grab-assignment/SKILL.md +0 -187
- package/platforms/claude-code/skills/plan-assignment/SKILL.md +0 -148
- package/platforms/claude-code/skills/syntaur-protocol/SKILL.md +0 -86
- package/platforms/codex/skills/complete-assignment/SKILL.md +0 -64
- package/platforms/codex/skills/create-assignment/SKILL.md +0 -49
- package/platforms/codex/skills/grab-assignment/SKILL.md +0 -71
- package/platforms/codex/skills/plan-assignment/SKILL.md +0 -57
- package/platforms/codex/skills/syntaur-protocol/SKILL.md +0 -102
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Syntaur statusline for Claude Code.
|
|
3
|
+
#
|
|
4
|
+
# Reads JSON from stdin per Claude Code's statusLine contract and prints a
|
|
5
|
+
# single line containing:
|
|
6
|
+
# [optional: output from a wrapped user script]
|
|
7
|
+
# <git repo:branch>
|
|
8
|
+
# <active syntaur assignment>
|
|
9
|
+
# <sessionId suffix>
|
|
10
|
+
#
|
|
11
|
+
# Wrapping: if SYNTAUR_STATUSLINE_WRAP names an executable, or the first
|
|
12
|
+
# non-empty line of $HOME/.syntaur/statusline.conf is a path to an executable,
|
|
13
|
+
# that script is invoked first with the same stdin; its stdout becomes the
|
|
14
|
+
# leading segment. This lets users who already had a custom statusline keep
|
|
15
|
+
# it while composing syntaur's extra info on the right.
|
|
16
|
+
#
|
|
17
|
+
# Never fails the terminal — always exits 0.
|
|
18
|
+
|
|
19
|
+
set -o pipefail 2>/dev/null || true
|
|
20
|
+
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
|
|
23
|
+
# Degrade cleanly if jq is unavailable. Emit just the marker so users notice.
|
|
24
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
25
|
+
printf '%s' '(syntaur: jq missing)'
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
SESSION_ID=""
|
|
30
|
+
CWD=""
|
|
31
|
+
|
|
32
|
+
if [ -n "$INPUT" ]; then
|
|
33
|
+
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
34
|
+
CWD=$(printf '%s' "$INPUT" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
[ -z "$CWD" ] && CWD="$PWD"
|
|
38
|
+
|
|
39
|
+
# --- Optional wrap: compose with an existing user script ---
|
|
40
|
+
WRAP_PATH="${SYNTAUR_STATUSLINE_WRAP:-}"
|
|
41
|
+
if [ -z "$WRAP_PATH" ] && [ -f "$HOME/.syntaur/statusline.conf" ]; then
|
|
42
|
+
# First non-empty, non-comment line is the wrap path.
|
|
43
|
+
WRAP_PATH=$(awk 'NF && !/^#/{print; exit}' "$HOME/.syntaur/statusline.conf" 2>/dev/null)
|
|
44
|
+
fi
|
|
45
|
+
WRAPPED_OUT=""
|
|
46
|
+
if [ -n "$WRAP_PATH" ] && [ -r "$WRAP_PATH" ]; then
|
|
47
|
+
# Run the wrapped script with the same stdin and a 2-second timeout (best-effort).
|
|
48
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
49
|
+
WRAPPED_OUT=$(printf '%s' "$INPUT" | timeout 2 bash "$WRAP_PATH" 2>/dev/null)
|
|
50
|
+
else
|
|
51
|
+
WRAPPED_OUT=$(printf '%s' "$INPUT" | bash "$WRAP_PATH" 2>/dev/null)
|
|
52
|
+
fi
|
|
53
|
+
# Collapse any trailing newlines so the composed line stays single-row.
|
|
54
|
+
WRAPPED_OUT=$(printf '%s' "$WRAPPED_OUT" | tr -d '\r' | awk 'NF{line=$0} END{print line}' 2>/dev/null)
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# --- Segment: git repo:branch ---
|
|
58
|
+
GIT_SEG=""
|
|
59
|
+
if [ -n "$CWD" ] && [ -d "$CWD" ]; then
|
|
60
|
+
GIT_ROOT=$(git --no-optional-locks -C "$CWD" rev-parse --show-toplevel 2>/dev/null)
|
|
61
|
+
if [ -n "$GIT_ROOT" ]; then
|
|
62
|
+
REPO=$(basename "$GIT_ROOT")
|
|
63
|
+
BRANCH=$(git --no-optional-locks -C "$CWD" symbolic-ref --short HEAD 2>/dev/null)
|
|
64
|
+
if [ -z "$BRANCH" ]; then
|
|
65
|
+
SHORT=$(git --no-optional-locks -C "$CWD" rev-parse --short HEAD 2>/dev/null)
|
|
66
|
+
[ -n "$SHORT" ] && BRANCH="detached@$SHORT"
|
|
67
|
+
fi
|
|
68
|
+
if [ -n "$BRANCH" ]; then
|
|
69
|
+
GIT_SEG="$REPO:$BRANCH"
|
|
70
|
+
else
|
|
71
|
+
GIT_SEG="$REPO"
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# --- Segment: active syntaur assignment ---
|
|
77
|
+
ASSIGNMENT_SEG=""
|
|
78
|
+
CONTEXT_FILE="$CWD/.syntaur/context.json"
|
|
79
|
+
if [ -f "$CONTEXT_FILE" ]; then
|
|
80
|
+
PROJECT_SLUG=$(jq -r '.projectSlug // empty' "$CONTEXT_FILE" 2>/dev/null)
|
|
81
|
+
ASSIGNMENT_SLUG=$(jq -r '.assignmentSlug // empty' "$CONTEXT_FILE" 2>/dev/null)
|
|
82
|
+
ASSIGNMENT_DIR=$(jq -r '.assignmentDir // empty' "$CONTEXT_FILE" 2>/dev/null)
|
|
83
|
+
|
|
84
|
+
TITLE=""
|
|
85
|
+
if [ -n "$ASSIGNMENT_DIR" ] && [ -f "$ASSIGNMENT_DIR/assignment.md" ]; then
|
|
86
|
+
TITLE=$(awk '/^title:/{sub(/^title:[[:space:]]*"?/,""); sub(/"?[[:space:]]*$/,""); print; exit}' "$ASSIGNMENT_DIR/assignment.md" 2>/dev/null)
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
LABEL=""
|
|
90
|
+
if [ -n "$PROJECT_SLUG" ] && [ -n "$ASSIGNMENT_SLUG" ]; then
|
|
91
|
+
LABEL="$PROJECT_SLUG/$ASSIGNMENT_SLUG"
|
|
92
|
+
elif [ -n "$ASSIGNMENT_SLUG" ]; then
|
|
93
|
+
LABEL="standalone/${ASSIGNMENT_SLUG:0:8}"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [ -n "$LABEL" ] && [ -n "$TITLE" ]; then
|
|
97
|
+
ASSIGNMENT_SEG="$LABEL — $TITLE"
|
|
98
|
+
elif [ -n "$LABEL" ]; then
|
|
99
|
+
ASSIGNMENT_SEG="$LABEL"
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# --- Segment: session id suffix ---
|
|
104
|
+
SESSION_SEG=""
|
|
105
|
+
if [ -n "$SESSION_ID" ]; then
|
|
106
|
+
LEN=${#SESSION_ID}
|
|
107
|
+
if [ "$LEN" -gt 8 ]; then
|
|
108
|
+
SESSION_SEG="…${SESSION_ID: -8}"
|
|
109
|
+
else
|
|
110
|
+
SESSION_SEG="$SESSION_ID"
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# --- Compose. Wrapped output (if any) leads; syntaur segments trail. ---
|
|
115
|
+
SYNTAUR_PARTS=""
|
|
116
|
+
for seg in "$GIT_SEG" "$ASSIGNMENT_SEG" "$SESSION_SEG"; do
|
|
117
|
+
if [ -n "$seg" ]; then
|
|
118
|
+
if [ -z "$SYNTAUR_PARTS" ]; then
|
|
119
|
+
SYNTAUR_PARTS="$seg"
|
|
120
|
+
else
|
|
121
|
+
SYNTAUR_PARTS="$SYNTAUR_PARTS · $seg"
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
done
|
|
125
|
+
|
|
126
|
+
if [ -n "$WRAPPED_OUT" ] && [ -n "$SYNTAUR_PARTS" ]; then
|
|
127
|
+
printf '%s · %s' "$WRAPPED_OUT" "$SYNTAUR_PARTS"
|
|
128
|
+
elif [ -n "$WRAPPED_OUT" ]; then
|
|
129
|
+
printf '%s' "$WRAPPED_OUT"
|
|
130
|
+
else
|
|
131
|
+
printf '%s' "$SYNTAUR_PARTS"
|
|
132
|
+
fi
|
|
133
|
+
exit 0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Prong Horn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# syntaur-skills
|
|
2
|
+
|
|
3
|
+
Agent-agnostic skills for the [Syntaur](https://github.com/prong-horn/syntaur) coordination protocol. Works with any AI coding agent — Claude Code, Cursor, Codex, OpenCode, and more.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Install the Syntaur CLI:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g syntaur
|
|
11
|
+
syntaur setup
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx skills add prong-horn/syntaur-skills
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or install a specific skill:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx skills add prong-horn/syntaur-skills --skill syntaur-protocol
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Skills
|
|
27
|
+
|
|
28
|
+
| Skill | Description |
|
|
29
|
+
|-------|-------------|
|
|
30
|
+
| `syntaur-protocol` | Core protocol knowledge — write boundaries, lifecycle states, conventions. Auto-activates when working with Syntaur files. |
|
|
31
|
+
| `grab-assignment` | Discover and claim a pending assignment from a project. Sets up working context. |
|
|
32
|
+
| `plan-assignment` | Create a detailed implementation plan for the current assignment. |
|
|
33
|
+
| `complete-assignment` | Write a handoff and transition an assignment to review or completed. |
|
|
34
|
+
| `create-project` | Create a new project with full scaffolding (manifest + indexes + resources + memories). |
|
|
35
|
+
| `create-assignment` | Create a new assignment within a project (or as a standalone one-off at `~/.syntaur/assignments/<uuid>/`). |
|
|
36
|
+
|
|
37
|
+
## How it works
|
|
38
|
+
|
|
39
|
+
Syntaur is a coordination protocol for AI agents built on markdown files. Projects contain assignments, assignments have lifecycle states, and agents follow write boundary rules about which files they can modify. Everything lives under `~/.syntaur/` and is managed via the `syntaur` CLI.
|
|
40
|
+
|
|
41
|
+
These skills teach your agent the protocol so it can participate in Syntaur-coordinated work — regardless of which coding agent you use.
|
|
42
|
+
|
|
43
|
+
For platform-specific integrations (hooks, commands, sandbox enforcement), see the [Syntaur plugin system](https://github.com/prong-horn/syntaur).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: complete-assignment
|
|
3
|
+
description: >-
|
|
4
|
+
Write a handoff and transition the current Syntaur assignment to review or completed.
|
|
5
|
+
Use when the user wants to finish an assignment, write a handoff, or submit work for review.
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
author: prong-horn
|
|
9
|
+
version: "1.1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Complete Assignment
|
|
13
|
+
|
|
14
|
+
Write a handoff for your current Syntaur assignment and transition it to `review` or `completed`.
|
|
15
|
+
|
|
16
|
+
## Input
|
|
17
|
+
|
|
18
|
+
Optional: the user may pass `--complete` to transition directly to `completed` instead of `review`. However, `--complete` is only allowed if ALL acceptance criteria are met AND every `## Todos` item is either checked or marked superseded. If any criterion or todo is unresolved, always transition to `review` regardless of the flag, and inform the user why.
|
|
19
|
+
|
|
20
|
+
## Step 1: Load Context
|
|
21
|
+
|
|
22
|
+
Read `.syntaur/context.json` from the current working directory.
|
|
23
|
+
|
|
24
|
+
If the file does not exist, tell the user: "No active assignment found. Run `grab-assignment` first."
|
|
25
|
+
|
|
26
|
+
Extract: `projectSlug`, `assignmentSlug`, `assignmentDir`, `projectDir`.
|
|
27
|
+
|
|
28
|
+
## Step 2: Load Playbooks
|
|
29
|
+
|
|
30
|
+
Read all playbook files from `~/.syntaur/playbooks/`:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ls ~/.syntaur/playbooks/*.md 2>/dev/null
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Verify your work complies with their rules. If any playbook has completion-related rules (e.g., "run tests before done"), follow them before proceeding.
|
|
37
|
+
|
|
38
|
+
## Step 3: Verify Acceptance Criteria and Todos
|
|
39
|
+
|
|
40
|
+
Read `<assignmentDir>/assignment.md` and find the `## Acceptance Criteria` and `## Todos` sections.
|
|
41
|
+
|
|
42
|
+
Review each acceptance criterion (checkbox item) AND each todo. Superseded todos marked `- [x] ~~Execute [...](./plan-v<N>.md)~~ (superseded by plan-v<N>)` count as resolved — they do not need to be done again.
|
|
43
|
+
|
|
44
|
+
For each:
|
|
45
|
+
- If you believe it is met / done, note why (what was implemented, where).
|
|
46
|
+
- If it is NOT met / done, flag it clearly.
|
|
47
|
+
|
|
48
|
+
If any acceptance criteria are unmet OR any todo is still `- [ ]` and not superseded, warn the user: "The following are not yet done: [list]. Do you want to proceed with the handoff anyway?" — stop if the user says no.
|
|
49
|
+
|
|
50
|
+
## Step 3.5: Append a Final Progress Entry
|
|
51
|
+
|
|
52
|
+
Before writing the handoff, append a final entry to `<assignmentDir>/progress.md` summarizing what was completed. The entry goes at the **top** of the body (reverse-chronological) under a new `## <ISO 8601 timestamp>` heading:
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
## <ISO 8601 timestamp>
|
|
56
|
+
|
|
57
|
+
<One paragraph summarizing the final state of work: what was implemented, what verifications passed, and any deliberate scope exclusions.>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Bump `entryCount` and set `updated` to the current timestamp in `progress.md`'s frontmatter.
|
|
61
|
+
|
|
62
|
+
Do NOT add a `## Progress` section to `assignment.md` — progress entries live exclusively in `progress.md` as of protocol v2.0.
|
|
63
|
+
|
|
64
|
+
## Step 4: Write Handoff Entry
|
|
65
|
+
|
|
66
|
+
Read `<assignmentDir>/handoff.md` to see its current content and frontmatter.
|
|
67
|
+
|
|
68
|
+
Append a new handoff entry to the markdown body. Read the current `handoffCount` from the frontmatter and use `handoffCount + 1` as the entry number. The entry must follow this format:
|
|
69
|
+
|
|
70
|
+
```markdown
|
|
71
|
+
## Handoff <N>: <ISO 8601 timestamp>
|
|
72
|
+
|
|
73
|
+
**From:** <your-agent-name>
|
|
74
|
+
**To:** human
|
|
75
|
+
**Reason:** <Why this handoff is happening, e.g., "Assignment complete, handing off for review.">
|
|
76
|
+
|
|
77
|
+
### Summary
|
|
78
|
+
<One paragraph summarizing what was accomplished and what remains>
|
|
79
|
+
|
|
80
|
+
### Current State
|
|
81
|
+
- <What is working>
|
|
82
|
+
- <What is not working or partially done>
|
|
83
|
+
- <Acceptance criteria status: N of M met>
|
|
84
|
+
|
|
85
|
+
### Next Steps
|
|
86
|
+
- <Recommended next actions for the reviewer or next agent>
|
|
87
|
+
|
|
88
|
+
### Important Context
|
|
89
|
+
- <Anything the next agent/human needs that is not in the assignment or plan>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Also update the handoff.md frontmatter: set `updated` to the current timestamp and increment the `handoffCount` by 1.
|
|
93
|
+
|
|
94
|
+
## Step 5: Update Checkboxes (Criteria + Todos)
|
|
95
|
+
|
|
96
|
+
In `<assignmentDir>/assignment.md`, update checkboxes in both the `## Acceptance Criteria` and `## Todos` sections to reflect the current state. Check off items that were completed (change `- [ ]` to `- [x]`).
|
|
97
|
+
|
|
98
|
+
Ideally, these should have been checked off incrementally during implementation. If they are already checked, verify they are still accurate. If some were missed, check them off now and note which were verified at completion time vs. during development in the handoff.
|
|
99
|
+
|
|
100
|
+
Do NOT uncheck or rewrite superseded todo lines matching `- [x] ~~...~~ (superseded by ...)` — preserve that history intact.
|
|
101
|
+
|
|
102
|
+
## Step 6: Close Session (optional)
|
|
103
|
+
|
|
104
|
+
If `.syntaur/context.json` includes a `sessionId` and the Syntaur dashboard is running, mark the session as completed:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
curl -s -X PATCH "http://localhost:$(cat ~/.syntaur/dashboard-port 2>/dev/null || echo 4800)/api/agent-sessions/<session-id>/status" \
|
|
108
|
+
-H "Content-Type: application/json" \
|
|
109
|
+
-d '{"status":"completed","projectSlug":"<project-slug>"}'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If this fails (e.g., dashboard not running), it is non-critical — the session will be reconciled automatically.
|
|
113
|
+
|
|
114
|
+
## Step 7: Transition Assignment State
|
|
115
|
+
|
|
116
|
+
If the user requested `--complete` and all criteria are met:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
syntaur complete <assignment-slug> --project <project-slug>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Otherwise, transition to review:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
syntaur review <assignment-slug> --project <project-slug>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If the command fails, report the error. Common failures:
|
|
129
|
+
- Assignment is not in `in_progress` status
|
|
130
|
+
- Project not found
|
|
131
|
+
|
|
132
|
+
## Step 8: Clean Up Context
|
|
133
|
+
|
|
134
|
+
Delete the context file:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
rm .syntaur/context.json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Step 9: Report to User
|
|
141
|
+
|
|
142
|
+
Summarize:
|
|
143
|
+
- Assignment slug and title
|
|
144
|
+
- New status (review or completed)
|
|
145
|
+
- Number of acceptance criteria met vs total
|
|
146
|
+
- If transitioned to `review`, a human reviewer will check the work. If any criteria were unmet, they may send it back to `in_progress`.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-assignment
|
|
3
|
+
description: >-
|
|
4
|
+
Create a new Syntaur assignment within a project (or as a standalone one-off).
|
|
5
|
+
Use when the user wants to add a task, create an assignment, or break down
|
|
6
|
+
work within a Syntaur project.
|
|
7
|
+
license: MIT
|
|
8
|
+
metadata:
|
|
9
|
+
author: prong-horn
|
|
10
|
+
version: "1.1.0"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Create Assignment
|
|
14
|
+
|
|
15
|
+
Create a new assignment — project-nested or standalone.
|
|
16
|
+
|
|
17
|
+
## Input
|
|
18
|
+
|
|
19
|
+
Expects arguments from the user:
|
|
20
|
+
|
|
21
|
+
- First (required): the assignment title (e.g., `"Add login endpoint"`)
|
|
22
|
+
- `--project <slug>` (required unless `--one-off`): the project to add the assignment to
|
|
23
|
+
- `--one-off` (optional): create a **standalone** assignment at `~/.syntaur/assignments/<uuid>/` with `project: null`. The folder is named by UUID; `slug` is display-only. `--depends-on` is not permitted for standalone assignments.
|
|
24
|
+
- `--slug <slug>` (optional): override the auto-generated assignment slug
|
|
25
|
+
- `--priority <level>` (optional): `low`, `medium` (default), `high`, or `critical`
|
|
26
|
+
- `--type <type>` (optional): classification such as `feature`, `bug`, `refactor`, `research`, `chore`. Defaults to `feature`. When `~/.syntaur/config.md` defines `types.definitions`, the CLI validates against that list.
|
|
27
|
+
- `--depends-on <slug[,slug...]>` (optional, project-nested only): comma-separated list of assignment slugs this depends on
|
|
28
|
+
- `--dir <path>` (optional): override the default project directory
|
|
29
|
+
|
|
30
|
+
If no title was provided, ask the user what the assignment should be called.
|
|
31
|
+
|
|
32
|
+
If neither `--project` nor `--one-off` was provided, check `.syntaur/context.json` for an active assignment. If present, default `--project` to that context's `projectSlug` and confirm with the user: "Add this assignment to project `<projectSlug>`?"
|
|
33
|
+
|
|
34
|
+
If no active context and no project flag, ask the user which project to add it to, or whether it should be a one-off.
|
|
35
|
+
|
|
36
|
+
## Step 1: Run the CLI
|
|
37
|
+
|
|
38
|
+
Build the command from the parsed arguments:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
syntaur create-assignment "<title>" --project <slug> [--slug <slug>] [--priority <level>] [--type <type>] [--depends-on <slugs>] [--dir <path>]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or for a one-off (standalone at `~/.syntaur/assignments/<uuid>/`):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
syntaur create-assignment "<title>" --one-off [--slug <slug>] [--priority <level>] [--type <type>] [--dir <path>]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If the command fails (e.g., project not found, slug collision, invalid type), report the error and suggest fixes.
|
|
51
|
+
|
|
52
|
+
## Step 2: Read the Created Assignment
|
|
53
|
+
|
|
54
|
+
After successful creation, extract the assignment slug (and for standalone, the UUID) and directory from the CLI output. Read the generated `assignment.md`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Project-nested:
|
|
58
|
+
cat ~/.syntaur/projects/<project-slug>/assignments/<assignment-slug>/assignment.md
|
|
59
|
+
|
|
60
|
+
# Standalone:
|
|
61
|
+
cat ~/.syntaur/assignments/<uuid>/assignment.md
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Step 3: Guide Next Steps
|
|
65
|
+
|
|
66
|
+
Tell the user:
|
|
67
|
+
- The assignment was created with its slug, priority, type, and location. For standalone assignments, note that the folder is named by UUID (not slug) — `slug` is display-only.
|
|
68
|
+
- Files created: `assignment.md`, `progress.md`, `comments.md`, `scratchpad.md`, `handoff.md`, `decision-record.md`. **`plan.md` is NOT scaffolded** — plan files are optional and created on demand by the `plan-assignment` skill.
|
|
69
|
+
- Remind the user: `progress.md` is where timestamped progress entries go (NOT `assignment.md`), and `comments.md` is CLI-mediated — write only via `syntaur comment <slug-or-uuid> "body" --type question|note|feedback [--reply-to <id>]`.
|
|
70
|
+
- Suggest editing `assignment.md` to fill in the objective, acceptance criteria, context, and any initial todos. The `## Todos` section accepts simple tasks or markdown links to plan files.
|
|
71
|
+
- If dependencies were set, note them. Standalone assignments cannot declare `dependsOn`.
|
|
72
|
+
- Suggest `grab-assignment <project-slug> <assignment-slug>` (or `grab-assignment --id <uuid>` for standalone) to claim and start working on it.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-project
|
|
3
|
+
description: >-
|
|
4
|
+
Create a new Syntaur project with full scaffolding (manifest, indexes,
|
|
5
|
+
resources, memories). Use when the user wants to start a new project or
|
|
6
|
+
initiative in Syntaur.
|
|
7
|
+
license: MIT
|
|
8
|
+
metadata:
|
|
9
|
+
author: prong-horn
|
|
10
|
+
version: "1.1.0"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Create Project
|
|
14
|
+
|
|
15
|
+
Create a new Syntaur project with full scaffolding.
|
|
16
|
+
|
|
17
|
+
## Input
|
|
18
|
+
|
|
19
|
+
Expects arguments from the user:
|
|
20
|
+
|
|
21
|
+
- First (required): the project title (e.g., `"Build Auth System"`)
|
|
22
|
+
- `--slug <slug>` (optional): override the auto-generated slug
|
|
23
|
+
- `--dir <path>` (optional): override the default project directory
|
|
24
|
+
- `--workspace <workspace>` (optional): workspace grouping label (e.g., `syntaur`, `reeva`)
|
|
25
|
+
|
|
26
|
+
If no title was provided, ask the user what the project should be called.
|
|
27
|
+
|
|
28
|
+
## Step 1: Run the CLI
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
syntaur create-project "<title>" [--slug <slug>] [--dir <path>] [--workspace <workspace>]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If the command fails (e.g., slug collision, empty title), report the error and suggest fixes.
|
|
35
|
+
|
|
36
|
+
## Step 2: Read the Created Project
|
|
37
|
+
|
|
38
|
+
Extract the project slug and directory from the CLI output. Read the generated `project.md` to confirm structure:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cat ~/.syntaur/projects/<slug>/project.md
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Step 3: Guide Next Steps
|
|
45
|
+
|
|
46
|
+
Tell the user:
|
|
47
|
+
|
|
48
|
+
- The project was created with its slug and location (`~/.syntaur/projects/<slug>/`).
|
|
49
|
+
- Key files scaffolded:
|
|
50
|
+
- `project.md` — human-authored goal and context (edit this).
|
|
51
|
+
- `manifest.md` — derived root navigation (do not edit directly).
|
|
52
|
+
- `_index-assignments.md`, `_index-plans.md`, `_index-decisions.md`, `_status.md` — derived indexes.
|
|
53
|
+
- `resources/_index.md` and `memories/_index.md` — shared-writable area scaffolding.
|
|
54
|
+
- Per-project `agent.md` / `claude.md` are NOT created — protocol v2.0 removed them. Agent-level conventions live at the repo root in `CLAUDE.md` / `AGENTS.md`, and user-defined behavioral rules live in `~/.syntaur/playbooks/<slug>.md`.
|
|
55
|
+
- Suggest they edit `project.md` to fill in the goal, scope, and context sections.
|
|
56
|
+
- Suggest running `create-assignment "<title>" --project <slug>` to add assignments to this project. Or `create-assignment "<title>" --one-off` for standalone work at `~/.syntaur/assignments/<uuid>/`.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grab-assignment
|
|
3
|
+
description: >-
|
|
4
|
+
Discover and claim a pending Syntaur assignment from a project (or a
|
|
5
|
+
standalone one-off). Use when the user wants to start working on a Syntaur
|
|
6
|
+
assignment, claim a task, or set up their working context.
|
|
7
|
+
license: MIT
|
|
8
|
+
metadata:
|
|
9
|
+
author: prong-horn
|
|
10
|
+
version: "1.1.0"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Grab Assignment
|
|
14
|
+
|
|
15
|
+
Claim a pending Syntaur assignment and set up the current workspace.
|
|
16
|
+
|
|
17
|
+
## Input
|
|
18
|
+
|
|
19
|
+
Expects up to two arguments from the user:
|
|
20
|
+
|
|
21
|
+
- First (required): the project slug (e.g., `build-auth-system`), OR `--id <uuid>` to claim a standalone assignment at `~/.syntaur/assignments/<uuid>/`.
|
|
22
|
+
- Second (optional, project-nested only): a specific assignment slug to grab. If omitted, list available pending assignments and pick one.
|
|
23
|
+
|
|
24
|
+
## Pre-flight Check
|
|
25
|
+
|
|
26
|
+
Check if `.syntaur/context.json` already exists in the current working directory.
|
|
27
|
+
|
|
28
|
+
- If it exists AND contains BOTH `projectSlug` and `assignmentSlug`, it represents an active assignment. Warn the user: "You already have an active assignment: `<assignmentSlug>` in project `<projectSlug>`. Grabbing a new one will replace this context. Proceed?" — stop if the user says no.
|
|
29
|
+
- If it exists but only has session fields (`sessionId`, `transcriptPath`) and no project/assignment, it was populated by the platform's SessionStart hook (Claude Code, etc.) and does NOT represent an active assignment. Proceed silently and merge assignment fields on top in Step 5.
|
|
30
|
+
|
|
31
|
+
## Step 1: Discover the Project (project-nested path)
|
|
32
|
+
|
|
33
|
+
For a project-nested grab, read the project entry files:
|
|
34
|
+
|
|
35
|
+
- `~/.syntaur/projects/<project-slug>/manifest.md`
|
|
36
|
+
- `~/.syntaur/projects/<project-slug>/project.md`
|
|
37
|
+
|
|
38
|
+
Note the `workspace` field in `project.md` frontmatter if present. Per-project `agent.md` / `claude.md` were removed in protocol v2.0 — repo-level `CLAUDE.md` / `AGENTS.md` and user playbooks under `~/.syntaur/playbooks/` take their place. Step 7 loads playbooks.
|
|
39
|
+
|
|
40
|
+
For a standalone grab (`--id <uuid>`), skip this step — there is no parent project.
|
|
41
|
+
|
|
42
|
+
## Step 2: Find Assignments
|
|
43
|
+
|
|
44
|
+
List assignment directories:
|
|
45
|
+
|
|
46
|
+
- Project-nested: `~/.syntaur/projects/<project-slug>/assignments/`
|
|
47
|
+
- Standalone: the single directory at `~/.syntaur/assignments/<uuid>/`
|
|
48
|
+
|
|
49
|
+
Do NOT filter by status — every assignment is grabbable. If a slug was provided, verify the directory exists. If no specific assignment was requested, read each `assignment.md` frontmatter and present the list with title, priority, and current status (highlighting `pending` as the likely default). Ask the user to choose unless there is exactly one obvious candidate.
|
|
50
|
+
|
|
51
|
+
## Step 3: Claim the Assignment
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Always safe at any status; does not transition state:
|
|
55
|
+
syntaur assign <assignment-slug> --agent <your-agent-name> --project <project-slug>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If the current status is `pending`, also run:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
syntaur start <assignment-slug> --project <project-slug>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Skip `start` for any non-`pending` status — grabbing must never rewind a `review`, `completed`, or `failed` assignment.
|
|
65
|
+
|
|
66
|
+
> **Agent identity:** Use an identifier for your agent platform — e.g., `claude`, `cursor`, `codex`, `opencode`.
|
|
67
|
+
|
|
68
|
+
If either command fails, report the error and stop.
|
|
69
|
+
|
|
70
|
+
## Step 4: Read Assignment Context and Backfill Workspace
|
|
71
|
+
|
|
72
|
+
Read the full assignment file. Also read `comments.md` if present (inherited questions / notes). For each `dependsOn` entry, read the dependency's `handoff.md` AND `decision-record.md` so upstream decisions carry forward.
|
|
73
|
+
|
|
74
|
+
From the assignment frontmatter extract: `title`, `workspace.repository`, `workspace.worktreePath`, `workspace.branch`, `dependsOn`, `priority`.
|
|
75
|
+
|
|
76
|
+
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
|
+
|
|
78
|
+
## Step 5: Create or Merge Context File
|
|
79
|
+
|
|
80
|
+
Merge assignment context into `.syntaur/context.json`. Never overwrite — if the file already exists (e.g., platform SessionStart hook populated `sessionId` / `transcriptPath`), preserve those fields.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
mkdir -p .syntaur
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Prepare the assignment payload:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"projectSlug": "<project-slug or null for standalone>",
|
|
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>",
|
|
96
|
+
"branch": "<workspace.branch or null>",
|
|
97
|
+
"grabbedAt": "<ISO 8601 timestamp>"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Merge it on top of whatever context.json already contains:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
if [ -f .syntaur/context.json ]; then
|
|
105
|
+
jq --slurpfile new <(echo "$NEW_CONTEXT_JSON") '. + $new[0]' .syntaur/context.json > .syntaur/context.json.tmp \
|
|
106
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
107
|
+
else
|
|
108
|
+
echo "$NEW_CONTEXT_JSON" > .syntaur/context.json
|
|
109
|
+
fi
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Use absolute paths (expand `~` to the home directory). If `workspace.repository` is a remote URL (e.g. `https://github.com/...`), set `workspaceRoot` to the current working directory instead.
|
|
113
|
+
|
|
114
|
+
## Step 6: Register Agent Session (real IDs only — no UUIDs)
|
|
115
|
+
|
|
116
|
+
`syntaur track-session` requires a `--session-id` from the agent runtime. Synthetic UUIDs are rejected. Source the real id in this order:
|
|
117
|
+
|
|
118
|
+
1. If `.syntaur/context.json` already has `sessionId` (platform SessionStart hook populated it), use it and the companion `transcriptPath` if present.
|
|
119
|
+
2. Otherwise, fall back to the per-agent lookup:
|
|
120
|
+
- **Claude Code**: the most-recently-modified `~/.claude/sessions/*.json` whose `cwd` matches `$(pwd)` — read its `sessionId`. The transcript path is `~/.claude/projects/<encoded-cwd>/<session-id>.jsonl` (omit if the file is absent).
|
|
121
|
+
- **Codex**: the most-recently-modified file under `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` whose first-line `session_meta.payload.cwd` matches `$(pwd)`. Use `payload.id` as the session id and the full rollout path as the transcript path.
|
|
122
|
+
- **Other agents**: use whatever real session identifier the runtime exposes. Do not invent one.
|
|
123
|
+
3. If no real id can be resolved, stop and tell the user to restart the session so the platform hook can populate it, or to run `/rename <assignment-slug>` (Claude Code) and retry.
|
|
124
|
+
|
|
125
|
+
After resolving, merge `sessionId` + `transcriptPath` back into context.json. Then register:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
syntaur track-session \
|
|
129
|
+
--project <project-slug> --assignment <assignment-slug> \
|
|
130
|
+
--agent <your-agent-name> \
|
|
131
|
+
--session-id <real-id> \
|
|
132
|
+
--transcript-path <path-if-known> \
|
|
133
|
+
--path $(pwd)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Omit `--transcript-path` entirely (don't pass an empty string) if no transcript path was resolved.
|
|
137
|
+
|
|
138
|
+
## Step 7: Load Playbooks
|
|
139
|
+
|
|
140
|
+
Read all playbook files from `~/.syntaur/playbooks/` and treat their content as active behavioral rules:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
ls ~/.syntaur/playbooks/*.md 2>/dev/null
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
For each file, read it and follow its directives. Playbooks take precedence over default conventions when they conflict.
|
|
147
|
+
|
|
148
|
+
## Step 8: Report to User
|
|
149
|
+
|
|
150
|
+
Summarize:
|
|
151
|
+
- Which assignment was grabbed (slug + title). Note if it was standalone (folder is the UUID, `slug` display-only).
|
|
152
|
+
- Current status (call it out explicitly if the assignment was already past `pending`).
|
|
153
|
+
- The objective (first paragraph from assignment.md body).
|
|
154
|
+
- The acceptance criteria (checkbox list).
|
|
155
|
+
- Active todos from `## Todos`, including any linked plan files.
|
|
156
|
+
- The workspace path.
|
|
157
|
+
- Any inherited comments/questions from `comments.md`.
|
|
158
|
+
- Suggested next step: `plan-assignment` to create an implementation plan.
|