syntaur 0.3.3 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +236 -49
  2. package/dist/index.js +886 -162
  3. package/dist/index.js.map +1 -1
  4. package/package.json +9 -2
  5. package/platforms/claude-code/.claude-plugin/plugin.json +1 -5
  6. package/platforms/claude-code/agents/syntaur-expert.md +30 -18
  7. package/platforms/claude-code/commands/complete-assignment/complete-assignment.md +20 -0
  8. package/platforms/claude-code/commands/create-assignment/create-assignment.md +20 -0
  9. package/platforms/claude-code/commands/create-project/create-project.md +20 -0
  10. package/platforms/claude-code/commands/grab-assignment/grab-assignment.md +20 -0
  11. package/platforms/claude-code/commands/plan-assignment/plan-assignment.md +20 -0
  12. package/statusline/statusline.sh +224 -0
  13. package/vendor/syntaur-skills/LICENSE +21 -0
  14. package/vendor/syntaur-skills/README.md +43 -0
  15. package/vendor/syntaur-skills/skills/complete-assignment/SKILL.md +146 -0
  16. package/vendor/syntaur-skills/skills/create-assignment/SKILL.md +72 -0
  17. package/vendor/syntaur-skills/skills/create-project/SKILL.md +56 -0
  18. package/vendor/syntaur-skills/skills/grab-assignment/SKILL.md +158 -0
  19. package/vendor/syntaur-skills/skills/plan-assignment/SKILL.md +137 -0
  20. package/vendor/syntaur-skills/skills/syntaur-protocol/SKILL.md +119 -0
  21. package/vendor/syntaur-skills/skills/syntaur-protocol/references/file-ownership.md +67 -0
  22. package/vendor/syntaur-skills/skills/syntaur-protocol/references/protocol-summary.md +82 -0
  23. package/platforms/claude-code/hooks/statusline.sh +0 -110
  24. package/platforms/claude-code/skills/complete-assignment/SKILL.md +0 -155
  25. package/platforms/claude-code/skills/create-assignment/SKILL.md +0 -67
  26. package/platforms/claude-code/skills/grab-assignment/SKILL.md +0 -202
  27. package/platforms/claude-code/skills/plan-assignment/SKILL.md +0 -156
  28. package/platforms/claude-code/skills/syntaur-protocol/SKILL.md +0 -86
  29. package/platforms/codex/skills/complete-assignment/SKILL.md +0 -64
  30. package/platforms/codex/skills/create-assignment/SKILL.md +0 -49
  31. package/platforms/codex/skills/grab-assignment/SKILL.md +0 -73
  32. package/platforms/codex/skills/plan-assignment/SKILL.md +0 -61
  33. package/platforms/codex/skills/syntaur-protocol/SKILL.md +0 -102
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syntaur",
3
- "version": "0.3.3",
3
+ "version": "0.4.1",
4
4
  "description": "Project workflow CLI with dashboard, Claude Code plugin, and Codex plugin",
5
5
  "homepage": "https://github.com/prong-horn/syntaur#readme",
6
6
  "repository": {
@@ -29,7 +29,11 @@
29
29
  ".agents",
30
30
  "platforms",
31
31
  "examples",
32
- "dashboard/dist"
32
+ "dashboard/dist",
33
+ "statusline",
34
+ "vendor/syntaur-skills/skills/**",
35
+ "vendor/syntaur-skills/LICENSE",
36
+ "vendor/syntaur-skills/README.md"
33
37
  ],
34
38
  "scripts": {
35
39
  "build": "tsup",
@@ -40,7 +44,9 @@
40
44
  "typecheck": "tsc --noEmit",
41
45
  "test": "vitest run",
42
46
  "test:watch": "vitest",
47
+ "prepack": "node scripts/verify-vendored-skills.mjs",
43
48
  "prepublishOnly": "npm run build && npm ci --prefix dashboard && npm run build --prefix dashboard",
49
+ "postinstall": "node scripts/postinstall-submodules.mjs",
44
50
  "try": "node scripts/try.mjs",
45
51
  "untry": "npm unlink -g syntaur && npm install -g syntaur@latest && echo '\\n✓ global syntaur restored to latest published version'"
46
52
  },
@@ -48,6 +54,7 @@
48
54
  "node": ">=20.0.0"
49
55
  },
50
56
  "dependencies": {
57
+ "@inquirer/prompts": "^8.4.2",
51
58
  "better-sqlite3": "^11.0.0",
52
59
  "chokidar": "^4.0.0",
53
60
  "commander": "^13.0.0",
@@ -5,9 +5,5 @@
5
5
  "name": "Brennen",
6
6
  "email": ""
7
7
  },
8
- "version": "0.1.8",
9
- "statusLine": {
10
- "type": "command",
11
- "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/statusline.sh"
12
- }
8
+ "version": "0.1.8"
13
9
  }
@@ -12,10 +12,12 @@ When answering questions, read the actual source files rather than relying solel
12
12
 
13
13
  ## Key Source Files
14
14
 
15
- - **Protocol summary:** `${CLAUDE_PLUGIN_ROOT}/references/protocol-summary.md`
15
+ - **Protocol summary:** `${CLAUDE_PLUGIN_ROOT}/references/protocol-summary.md` (or `~/.claude/skills/syntaur-protocol/references/protocol-summary.md` for the installed skill version)
16
16
  - **File ownership:** `${CLAUDE_PLUGIN_ROOT}/references/file-ownership.md`
17
17
  - **Plugin manifest:** `${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json`
18
- - **Skills:** `${CLAUDE_PLUGIN_ROOT}/skills/`
18
+ - **Protocol skills (installed by `syntaur install-plugin`):** `~/.claude/skills/{syntaur-protocol,grab-assignment,plan-assignment,complete-assignment,create-assignment,create-project}/`
19
+ - **Protocol skills source (vendored via submodule):** `<syntaur-repo>/vendor/syntaur-skills/skills/` — standalone repo at https://github.com/prong-horn/syntaur-skills
20
+ - **Slash commands (ship in plugin):** `${CLAUDE_PLUGIN_ROOT}/commands/` — thin wrappers that invoke the corresponding installed skill
19
21
  - **Hooks:** `${CLAUDE_PLUGIN_ROOT}/hooks/`
20
22
 
21
23
  For the live CLI surface, run `syntaur --help` in the user environment.
@@ -204,28 +206,38 @@ The Syntaur Claude Code plugin is installed by `syntaur install-plugin`, which r
204
206
  ```
205
207
  plugin/
206
208
  .claude-plugin/
207
- plugin.json # Plugin metadata
209
+ plugin.json # Plugin metadata
208
210
  agents/
209
- syntaur-expert.md # This agent
210
- skills/
211
- syntaur-protocol/SKILL.md # Core protocol rules (background)
212
- grab-assignment/SKILL.md # Claim a pending assignment
213
- create-project/SKILL.md # Create new project
214
- create-assignment/SKILL.md # Create new assignment
215
- plan-assignment/SKILL.md # Write implementation plan
216
- complete-assignment/SKILL.md # Handoff and complete
211
+ syntaur-expert.md # This agent
217
212
  commands/
218
- track-session/track-session.md # Register tmux sessions
213
+ grab-assignment/grab-assignment.md # Slash wrapper for grab-assignment skill
214
+ plan-assignment/plan-assignment.md # Slash wrapper for plan-assignment skill
215
+ complete-assignment/complete-assignment.md # Slash wrapper for complete-assignment skill
216
+ create-assignment/create-assignment.md # Slash wrapper for create-assignment skill
217
+ create-project/create-project.md # Slash wrapper for create-project skill
218
+ track-session/track-session.md # Claude-specific session registration
219
+ doctor-syntaur/... # Diagnose install
220
+ track-server/... # Register a running server
219
221
  hooks/
220
- hooks.json # Hook definitions
221
- session-start.sh # Merge real session_id + transcript_path into existing .syntaur/context.json
222
- session-cleanup.sh # Mark sessions stopped on exit
223
- enforce-boundaries.sh # Write boundary enforcement
222
+ hooks.json # Hook definitions
223
+ session-start.sh # Merge real session_id + transcript_path into existing .syntaur/context.json
224
+ session-cleanup.sh # Mark sessions stopped on exit
225
+ enforce-boundaries.sh # Write boundary enforcement
224
226
  references/
225
- protocol-summary.md # One-page protocol quick reference
226
- file-ownership.md # Write boundary rules
227
+ protocol-summary.md # One-page protocol quick reference
228
+ file-ownership.md # Write boundary rules
229
+
230
+ ~/.claude/skills/ # Installed by `syntaur install-plugin` (vendored from syntaur-skills repo)
231
+ syntaur-protocol/SKILL.md # Auto-activates on Syntaur file contexts
232
+ grab-assignment/SKILL.md
233
+ plan-assignment/SKILL.md
234
+ complete-assignment/SKILL.md
235
+ create-assignment/SKILL.md
236
+ create-project/SKILL.md
227
237
  ```
228
238
 
239
+ Slash commands (`/grab-assignment` etc.) are thin wrappers that delegate to the installed skills. This lets the same protocol skills work in Claude Code (via slash command + auto-activation) and Codex (via auto-activation only).
240
+
229
241
  ### Skills Summary
230
242
 
231
243
  | Skill | Trigger | Purpose |
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: complete-assignment
3
+ description: Append a progress entry + handoff and transition the current Syntaur assignment to review or completed
4
+ arguments:
5
+ - name: args
6
+ description: "Optional — see the complete-assignment skill for supported flags"
7
+ required: false
8
+ ---
9
+
10
+ # /complete-assignment
11
+
12
+ Thin wrapper that invokes the `complete-assignment` skill. The skill lives in `~/.claude/skills/complete-assignment/` (installed by `syntaur setup` / `syntaur install-plugin`) and contains the full protocol — verifying acceptance criteria and todos, appending a progress.md entry, writing a handoff.md section, and calling `syntaur review` or `syntaur complete`.
13
+
14
+ ## Instructions
15
+
16
+ Invoke the `complete-assignment` skill via the Skill tool, passing the user's arguments. The skill handles everything else.
17
+
18
+ Arguments: $ARGUMENTS
19
+
20
+ If the skill is not installed, tell the user to run `syntaur install-plugin` (or `syntaur setup` if they haven't set up yet).
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: create-assignment
3
+ description: Create a new Syntaur assignment (project-nested or standalone one-off)
4
+ arguments:
5
+ - name: args
6
+ description: "Title and flags. See the create-assignment skill for supported forms (e.g. --project <slug>, --one-off, --type <type>)."
7
+ required: false
8
+ ---
9
+
10
+ # /create-assignment
11
+
12
+ Thin wrapper that invokes the `create-assignment` skill. The skill lives in `~/.claude/skills/create-assignment/` (installed by `syntaur setup` / `syntaur install-plugin`) and contains the full protocol — picking project-nested or standalone, validating the type, scaffolding assignment.md / progress.md / comments.md.
13
+
14
+ ## Instructions
15
+
16
+ Invoke the `create-assignment` skill via the Skill tool, passing the user's arguments. The skill handles everything else.
17
+
18
+ Arguments: $ARGUMENTS
19
+
20
+ If the skill is not installed, tell the user to run `syntaur install-plugin` (or `syntaur setup` if they haven't set up yet).
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: create-project
3
+ description: Create a new Syntaur project with full scaffolding
4
+ arguments:
5
+ - name: args
6
+ description: "Title and optional flags (--slug, --dir, --workspace). See the create-project skill for full usage."
7
+ required: false
8
+ ---
9
+
10
+ # /create-project
11
+
12
+ Thin wrapper that invokes the `create-project` skill. The skill lives in `~/.claude/skills/create-project/` (installed by `syntaur setup` / `syntaur install-plugin`) and contains the full protocol — calling `syntaur create-project`, reading the generated project.md, and guiding next steps.
13
+
14
+ ## Instructions
15
+
16
+ Invoke the `create-project` skill via the Skill tool, passing the user's arguments. The skill handles everything else.
17
+
18
+ Arguments: $ARGUMENTS
19
+
20
+ If the skill is not installed, tell the user to run `syntaur install-plugin` (or `syntaur setup` if they haven't set up yet).
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: grab-assignment
3
+ description: Claim a Syntaur assignment and load it into the current working context
4
+ arguments:
5
+ - name: args
6
+ description: "Project slug and optional assignment slug, or --id <uuid> for standalone. See the grab-assignment skill for full forms."
7
+ required: false
8
+ ---
9
+
10
+ # /grab-assignment
11
+
12
+ Thin wrapper that invokes the `grab-assignment` skill. The skill lives in `~/.claude/skills/grab-assignment/` (installed by `syntaur setup` / `syntaur install-plugin`) and contains the full protocol — discovering pending assignments, merging `.syntaur/context.json`, registering the agent session, reading the assignment.
13
+
14
+ ## Instructions
15
+
16
+ Invoke the `grab-assignment` skill via the Skill tool, passing the user's arguments. The skill handles everything else.
17
+
18
+ Arguments: $ARGUMENTS
19
+
20
+ If the skill is not installed, tell the user to run `syntaur install-plugin` (or `syntaur setup` if they haven't set up yet).
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: plan-assignment
3
+ description: Create a detailed implementation plan for the current Syntaur assignment
4
+ arguments:
5
+ - name: args
6
+ description: "Optional — see the plan-assignment skill for supported flags"
7
+ required: false
8
+ ---
9
+
10
+ # /plan-assignment
11
+
12
+ Thin wrapper that invokes the `plan-assignment` skill. The skill lives in `~/.claude/skills/plan-assignment/` (installed by `syntaur setup` / `syntaur install-plugin`) and contains the full protocol — picking the next `plan-v<N>.md`, writing it, appending a `## Todos` entry, marking any prior plan todo superseded, and recording key decisions in `decision-record.md`.
13
+
14
+ ## Instructions
15
+
16
+ Invoke the `plan-assignment` skill via the Skill tool, passing the user's arguments. The skill handles everything else.
17
+
18
+ Arguments: $ARGUMENTS
19
+
20
+ If the skill is not installed, tell the user to run `syntaur install-plugin` (or `syntaur setup` if they haven't set up yet).
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env bash
2
+ # Syntaur statusline for Claude Code.
3
+ #
4
+ # Reads JSON from stdin per Claude Code's statusLine contract and renders a
5
+ # user-configurable single line composed of the segments listed in
6
+ # $HOME/.syntaur/statusline.config.json
7
+ # with shape:
8
+ # { "segments": ["wrap","git","assignment","model","ctx","session"],
9
+ # "separator": " · ",
10
+ # "wrap": "/optional/path/to/inner-statusline.sh" }
11
+ #
12
+ # Available segments:
13
+ # wrap stdout of an external script (composes another statusline)
14
+ # git repo:branch (+ dirty marker + ahead/behind counts)
15
+ # assignment active syntaur assignment (project/slug or standalone/uuid — title)
16
+ # session Claude session id, last 8 chars prefixed by "…"
17
+ # model Claude model display name
18
+ # ctx context window fill bar, e.g. "ctx:[####------] 42%"
19
+ # cwd basename of the current working directory
20
+ #
21
+ # If the config file is absent, falls back to a sensible default set.
22
+ # Never fails the terminal — always exits 0.
23
+
24
+ set -o pipefail 2>/dev/null || true
25
+
26
+ INPUT=$(cat)
27
+
28
+ if ! command -v jq >/dev/null 2>&1; then
29
+ printf '%s' '(syntaur: jq missing)'
30
+ exit 0
31
+ fi
32
+
33
+ CONFIG_FILE="$HOME/.syntaur/statusline.config.json"
34
+ # Fall back to a simple one-line conf file for backward compat with earlier
35
+ # install-statusline versions that only stored a wrap target.
36
+ LEGACY_CONF="$HOME/.syntaur/statusline.conf"
37
+
38
+ # --- Load config ---
39
+ SEGMENTS_RAW=""
40
+ SEPARATOR=" · "
41
+ WRAP_PATH=""
42
+
43
+ if [ -f "$CONFIG_FILE" ]; then
44
+ SEGMENTS_RAW=$(jq -r '(.segments // []) | join(",")' "$CONFIG_FILE" 2>/dev/null)
45
+ SEP_FROM_CONF=$(jq -r '.separator // empty' "$CONFIG_FILE" 2>/dev/null)
46
+ [ -n "$SEP_FROM_CONF" ] && SEPARATOR="$SEP_FROM_CONF"
47
+ WRAP_PATH=$(jq -r '.wrap // empty' "$CONFIG_FILE" 2>/dev/null)
48
+ fi
49
+
50
+ # Env var always takes precedence for wrap (useful for testing).
51
+ [ -n "$SYNTAUR_STATUSLINE_WRAP" ] && WRAP_PATH="$SYNTAUR_STATUSLINE_WRAP"
52
+
53
+ # Legacy conf: first non-empty, non-comment line is wrap path.
54
+ if [ -z "$WRAP_PATH" ] && [ -f "$LEGACY_CONF" ]; then
55
+ WRAP_PATH=$(awk 'NF && !/^#/{print; exit}' "$LEGACY_CONF" 2>/dev/null)
56
+ fi
57
+
58
+ # Default segment set if none configured.
59
+ if [ -z "$SEGMENTS_RAW" ]; then
60
+ # Default: include wrap as leading segment only if a wrap path is set.
61
+ if [ -n "$WRAP_PATH" ]; then
62
+ SEGMENTS_RAW="wrap,git,assignment,session"
63
+ else
64
+ SEGMENTS_RAW="git,assignment,session"
65
+ fi
66
+ fi
67
+
68
+ # --- Extract stdin fields ---
69
+ SESSION_ID=""
70
+ CWD=""
71
+ MODEL=""
72
+ USED_PCT=""
73
+
74
+ if [ -n "$INPUT" ]; then
75
+ SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
76
+ CWD=$(printf '%s' "$INPUT" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
77
+ MODEL=$(printf '%s' "$INPUT" | jq -r '.model.display_name // empty' 2>/dev/null)
78
+ USED_PCT=$(printf '%s' "$INPUT" | jq -r '.context_window.used_percentage // empty' 2>/dev/null)
79
+ fi
80
+
81
+ [ -z "$CWD" ] && CWD="$PWD"
82
+
83
+ # --- Compute each available segment value (cheap, unconditional). ---
84
+
85
+ # wrap
86
+ WRAP_SEG=""
87
+ if [ -n "$WRAP_PATH" ] && [ -r "$WRAP_PATH" ]; then
88
+ if command -v timeout >/dev/null 2>&1; then
89
+ WRAP_SEG=$(printf '%s' "$INPUT" | timeout 2 bash "$WRAP_PATH" 2>/dev/null)
90
+ else
91
+ WRAP_SEG=$(printf '%s' "$INPUT" | bash "$WRAP_PATH" 2>/dev/null)
92
+ fi
93
+ # Take last non-empty line (collapse to single row).
94
+ WRAP_SEG=$(printf '%s' "$WRAP_SEG" | tr -d '\r' | awk 'NF{line=$0} END{print line}' 2>/dev/null)
95
+ fi
96
+
97
+ # git — repo:branch[*] +ahead -behind
98
+ GIT_SEG=""
99
+ if [ -d "$CWD" ]; then
100
+ GIT_ROOT=$(git --no-optional-locks -C "$CWD" rev-parse --show-toplevel 2>/dev/null)
101
+ if [ -n "$GIT_ROOT" ]; then
102
+ REPO=$(basename "$GIT_ROOT")
103
+ BRANCH=$(git --no-optional-locks -C "$CWD" symbolic-ref --short HEAD 2>/dev/null)
104
+ if [ -z "$BRANCH" ]; then
105
+ SHORT=$(git --no-optional-locks -C "$CWD" rev-parse --short HEAD 2>/dev/null)
106
+ [ -n "$SHORT" ] && BRANCH="detached@$SHORT"
107
+ fi
108
+
109
+ DIRTY=""
110
+ if ! git --no-optional-locks -C "$CWD" diff --quiet 2>/dev/null \
111
+ || ! git --no-optional-locks -C "$CWD" diff --cached --quiet 2>/dev/null; then
112
+ DIRTY="*"
113
+ fi
114
+
115
+ AHEAD_BEHIND=""
116
+ UPSTREAM=$(git --no-optional-locks -C "$CWD" rev-parse --abbrev-ref --symbolic-full-name "@{u}" 2>/dev/null)
117
+ if [ -n "$UPSTREAM" ]; then
118
+ AHEAD=$(git --no-optional-locks -C "$CWD" rev-list --count "$UPSTREAM..HEAD" 2>/dev/null)
119
+ BEHIND=$(git --no-optional-locks -C "$CWD" rev-list --count "HEAD..$UPSTREAM" 2>/dev/null)
120
+ [ "${AHEAD:-0}" -gt 0 ] 2>/dev/null && AHEAD_BEHIND=" +${AHEAD}"
121
+ [ "${BEHIND:-0}" -gt 0 ] 2>/dev/null && AHEAD_BEHIND="${AHEAD_BEHIND} -${BEHIND}"
122
+ fi
123
+
124
+ if [ -n "$BRANCH" ]; then
125
+ GIT_SEG="${REPO}:${BRANCH}${DIRTY}${AHEAD_BEHIND}"
126
+ else
127
+ GIT_SEG="$REPO"
128
+ fi
129
+ fi
130
+ fi
131
+
132
+ # assignment — project/slug — title (or standalone/uuid-prefix — title)
133
+ ASSIGNMENT_SEG=""
134
+ CONTEXT_FILE="$CWD/.syntaur/context.json"
135
+ if [ -f "$CONTEXT_FILE" ]; then
136
+ PROJECT_SLUG=$(jq -r '.projectSlug // empty' "$CONTEXT_FILE" 2>/dev/null)
137
+ ASSIGNMENT_SLUG=$(jq -r '.assignmentSlug // empty' "$CONTEXT_FILE" 2>/dev/null)
138
+ ASSIGNMENT_DIR=$(jq -r '.assignmentDir // empty' "$CONTEXT_FILE" 2>/dev/null)
139
+ TITLE=""
140
+ if [ -n "$ASSIGNMENT_DIR" ] && [ -f "$ASSIGNMENT_DIR/assignment.md" ]; then
141
+ TITLE=$(awk '/^title:/{sub(/^title:[[:space:]]*"?/,""); sub(/"?[[:space:]]*$/,""); print; exit}' "$ASSIGNMENT_DIR/assignment.md" 2>/dev/null)
142
+ fi
143
+ LABEL=""
144
+ if [ -n "$PROJECT_SLUG" ] && [ -n "$ASSIGNMENT_SLUG" ]; then
145
+ LABEL="$PROJECT_SLUG/$ASSIGNMENT_SLUG"
146
+ elif [ -n "$ASSIGNMENT_SLUG" ]; then
147
+ LABEL="standalone/${ASSIGNMENT_SLUG:0:8}"
148
+ fi
149
+ if [ -n "$LABEL" ] && [ -n "$TITLE" ]; then
150
+ ASSIGNMENT_SEG="$LABEL — $TITLE"
151
+ elif [ -n "$LABEL" ]; then
152
+ ASSIGNMENT_SEG="$LABEL"
153
+ fi
154
+ fi
155
+
156
+ # session — last 8 chars
157
+ SESSION_SEG=""
158
+ if [ -n "$SESSION_ID" ]; then
159
+ LEN=${#SESSION_ID}
160
+ if [ "$LEN" -gt 8 ]; then
161
+ SESSION_SEG="…${SESSION_ID: -8}"
162
+ else
163
+ SESSION_SEG="$SESSION_ID"
164
+ fi
165
+ fi
166
+
167
+ # model
168
+ MODEL_SEG=""
169
+ [ -n "$MODEL" ] && MODEL_SEG="$MODEL"
170
+
171
+ # ctx — fill bar
172
+ CTX_SEG=""
173
+ if [ -n "$USED_PCT" ]; then
174
+ USED_INT=$(printf "%.0f" "$USED_PCT" 2>/dev/null || echo "$USED_PCT")
175
+ if [ -n "$USED_INT" ] && [ "$USED_INT" -ge 0 ] 2>/dev/null; then
176
+ FILLED=$(( USED_INT / 10 ))
177
+ [ "$FILLED" -gt 10 ] && FILLED=10
178
+ EMPTY=$(( 10 - FILLED ))
179
+ BAR=""
180
+ i=0
181
+ while [ "$i" -lt "$FILLED" ]; do BAR="${BAR}#"; i=$((i+1)); done
182
+ i=0
183
+ while [ "$i" -lt "$EMPTY" ]; do BAR="${BAR}-"; i=$((i+1)); done
184
+ CTX_SEG="ctx:[${BAR}] ${USED_INT}%"
185
+ fi
186
+ fi
187
+
188
+ # cwd — basename
189
+ CWD_SEG=""
190
+ [ -n "$CWD" ] && CWD_SEG=$(basename "$CWD")
191
+
192
+ # --- Emit the selected segments in order ---
193
+ OUT=""
194
+ # Split SEGMENTS_RAW on commas using IFS.
195
+ OLD_IFS="$IFS"
196
+ IFS=','
197
+ for name in $SEGMENTS_RAW; do
198
+ IFS="$OLD_IFS"
199
+ # Trim whitespace
200
+ name=$(printf '%s' "$name" | awk '{$1=$1; print}')
201
+ value=""
202
+ case "$name" in
203
+ wrap) value="$WRAP_SEG" ;;
204
+ git) value="$GIT_SEG" ;;
205
+ assignment) value="$ASSIGNMENT_SEG" ;;
206
+ session) value="$SESSION_SEG" ;;
207
+ model) value="$MODEL_SEG" ;;
208
+ ctx) value="$CTX_SEG" ;;
209
+ cwd) value="$CWD_SEG" ;;
210
+ *) value="" ;;
211
+ esac
212
+ if [ -n "$value" ]; then
213
+ if [ -z "$OUT" ]; then
214
+ OUT="$value"
215
+ else
216
+ OUT="${OUT}${SEPARATOR}${value}"
217
+ fi
218
+ fi
219
+ IFS=','
220
+ done
221
+ IFS="$OLD_IFS"
222
+
223
+ printf '%s' "$OUT"
224
+ 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`.