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.
- package/README.md +236 -49
- package/dist/index.js +886 -162
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -5
- package/platforms/claude-code/agents/syntaur-expert.md +30 -18
- 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/statusline/statusline.sh +224 -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/hooks/statusline.sh +0 -110
- 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 -202
- package/platforms/claude-code/skills/plan-assignment/SKILL.md +0 -156
- 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 -73
- package/platforms/codex/skills/plan-assignment/SKILL.md +0 -61
- 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
|
+
"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",
|
|
@@ -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
|
-
- **
|
|
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
|
|
209
|
+
plugin.json # Plugin metadata
|
|
208
210
|
agents/
|
|
209
|
-
syntaur-expert.md
|
|
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
|
-
|
|
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
|
|
221
|
-
session-start.sh
|
|
222
|
-
session-cleanup.sh
|
|
223
|
-
enforce-boundaries.sh
|
|
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
|
|
226
|
-
file-ownership.md
|
|
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`.
|