@firatcand/roster 0.4.0 → 1.0.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 (76) hide show
  1. package/README.md +79 -219
  2. package/agents/lesson-drafter.md +3 -8
  3. package/agents/pattern-detector.md +0 -1
  4. package/bin/roster.js +1407 -217
  5. package/package.json +2 -3
  6. package/skills/chief-of-staff/SKILL.md +62 -78
  7. package/skills/dreamer/SKILL.md +8 -7
  8. package/skills/roster-orchestrator/SKILL.md +53 -25
  9. package/templates/CLAUDE.project.template.md +1 -1
  10. package/templates/CONTEXT.template.md +2 -2
  11. package/templates/gitignore-defaults.txt +2 -0
  12. package/templates/scaffold/chief-of-staff/README.md +16 -24
  13. package/templates/scaffold/chief-of-staff/agent.md +22 -32
  14. package/templates/scaffold/chief-of-staff/plans/audit-agent.yaml +4 -4
  15. package/templates/scaffold/chief-of-staff/plans/audit-repo.yaml +5 -4
  16. package/templates/scaffold/chief-of-staff/plans/create-agent.yaml +5 -34
  17. package/templates/scaffold/config/project.yaml.template +10 -0
  18. package/templates/scaffold/conventions.md +159 -171
  19. package/templates/scaffold/dreamer/README.md +2 -2
  20. package/templates/scaffold/dreamer/agent.md +0 -1
  21. package/templates/scaffold/dreamer/plans/nightly-reflection.yaml +23 -37
  22. package/templates/scaffold/dreamer/subagents/lesson-drafter.md +2 -7
  23. package/templates/scaffold/{projects/_demo/guidelines → guidelines}/asset-links.md +4 -0
  24. package/templates/scaffold/{projects/_demo/guidelines → guidelines}/brand-book.md +4 -0
  25. package/templates/scaffold/{projects/_demo/guidelines → guidelines}/messaging.md +4 -0
  26. package/templates/scaffold/{projects/_demo/guidelines → guidelines}/voice.md +4 -0
  27. package/templates/scaffold/scripts/audit-agent.sh +74 -47
  28. package/templates/scaffold/scripts/audit-repo.sh +27 -49
  29. package/templates/scaffold/scripts/create-function.sh +1 -1
  30. package/templates/scaffold/scripts/lib/README.md +1 -1
  31. package/templates/scaffold/scripts/lib/bindings-prompt.sh +43 -124
  32. package/templates/scaffold/scripts/new-agent.sh +99 -91
  33. package/templates/scaffold/scripts/rename-agent.sh +91 -0
  34. package/templates/scaffold/scripts/save-state.sh +32 -0
  35. package/agents/critic.md +0 -74
  36. package/agents/enricher.md +0 -56
  37. package/agents/promotion-arbiter.md +0 -71
  38. package/agents/prospector.md +0 -51
  39. package/agents/writer.md +0 -58
  40. package/skills/sdr/SKILL.md +0 -147
  41. package/templates/scaffold/chief-of-staff/plans/add-agent-to-project.yaml +0 -45
  42. package/templates/scaffold/chief-of-staff/plans/archive-project.yaml +0 -51
  43. package/templates/scaffold/chief-of-staff/plans/audit-project.yaml +0 -34
  44. package/templates/scaffold/chief-of-staff/plans/create-project.yaml +0 -65
  45. package/templates/scaffold/chief-of-staff/plans/remove-agent-from-project.yaml +0 -50
  46. package/templates/scaffold/chief-of-staff/plans/rename-project.yaml +0 -62
  47. package/templates/scaffold/chief-of-staff/plans/unarchive-project.yaml +0 -41
  48. package/templates/scaffold/dreamer/subagents/promotion-arbiter.md +0 -64
  49. package/templates/scaffold/gtm/sdr/.claude/settings.json +0 -3
  50. package/templates/scaffold/gtm/sdr/.mcp.json +0 -21
  51. package/templates/scaffold/gtm/sdr/README.md +0 -41
  52. package/templates/scaffold/gtm/sdr/agent.md +0 -136
  53. package/templates/scaffold/gtm/sdr/plans/cold-outreach.yaml +0 -92
  54. package/templates/scaffold/gtm/sdr/projects/_demo/asset-references.md +0 -7
  55. package/templates/scaffold/gtm/sdr/projects/_demo/config/default.yaml +0 -69
  56. package/templates/scaffold/gtm/sdr/projects/_demo/log/feedback/.gitkeep +0 -0
  57. package/templates/scaffold/gtm/sdr/projects/_demo/log/runs/.gitkeep +0 -0
  58. package/templates/scaffold/gtm/sdr/projects/_demo/playbook/.gitkeep +0 -0
  59. package/templates/scaffold/gtm/sdr/subagents/critic.md +0 -67
  60. package/templates/scaffold/gtm/sdr/subagents/enricher.md +0 -49
  61. package/templates/scaffold/gtm/sdr/subagents/prospector.md +0 -44
  62. package/templates/scaffold/gtm/sdr/subagents/writer.md +0 -51
  63. package/templates/scaffold/projects/_demo/CLAUDE.md +0 -35
  64. package/templates/scaffold/projects/_demo/README.md +0 -16
  65. package/templates/scaffold/projects/_demo/assets/.gitkeep +0 -0
  66. package/templates/scaffold/projects/_demo/config/default.yaml +0 -28
  67. package/templates/scaffold/projects/_demo/state.md +0 -11
  68. package/templates/scaffold/scripts/archive-project.sh +0 -98
  69. package/templates/scaffold/scripts/audit-project.sh +0 -361
  70. package/templates/scaffold/scripts/new-agent-instance.sh +0 -114
  71. package/templates/scaffold/scripts/new-project.sh +0 -125
  72. package/templates/scaffold/scripts/remove-agent-from-project.sh +0 -67
  73. package/templates/scaffold/scripts/rename-project.sh +0 -118
  74. package/templates/scaffold/scripts/unarchive-project.sh +0 -115
  75. /package/templates/scaffold/gtm/{sdr/playbook/.gitkeep → .gitkeep} +0 -0
  76. /package/templates/scaffold/{projects/_demo/guidelines → guidelines}/icps/_persona-template.md +0 -0
@@ -1,361 +0,0 @@
1
- #!/usr/bin/env bash
2
- # audit-project.sh — checks project completeness, reports issues with suggested fixes
3
- # Usage: bash scripts/audit-project.sh <project>
4
-
5
- set -euo pipefail
6
-
7
- if [ $# -ne 1 ]; then
8
- echo "Usage: $0 <project>"
9
- exit 1
10
- fi
11
-
12
- PROJECT="$1"
13
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
14
- PROJECT_DIR="$ROOT/projects/$PROJECT"
15
-
16
- if [ ! -d "$PROJECT_DIR" ]; then
17
- echo "ERROR: Project '$PROJECT' not found at $PROJECT_DIR"
18
- exit 1
19
- fi
20
-
21
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
22
- RUN_TIME=$(date +%Y-%m-%d-%H%M)
23
- LOG_DIR="$ROOT/chief-of-staff/logs/$(date +%Y-%m)"
24
- mkdir -p "$LOG_DIR"
25
- REPORT="$LOG_DIR/audit-$PROJECT-$RUN_TIME.md"
26
-
27
- # Buffers
28
- FAILURES=()
29
- WARNINGS=()
30
- PASSED=()
31
-
32
- # Check helper: file exists and isn't template content
33
- is_template() {
34
- local file="$1"
35
- # Heuristic: contains a placeholder pattern like <something descriptive>
36
- # We use the simple heuristic of looking for "<3 adjectives" or "<list>" — common template strings
37
- if grep -qE '<[a-z0-9 ,/.:-]+>' "$file" 2>/dev/null; then
38
- return 0
39
- fi
40
- return 1
41
- }
42
-
43
- check_required_guideline() {
44
- local file="$1"
45
- local rel="${file#$ROOT/}"
46
- if [ ! -f "$file" ]; then
47
- FAILURES+=("[$rel] required file missing")
48
- FAILURES+=(" → Suggested fix: copy from projects/_template/${rel#projects/$PROJECT/}")
49
- return
50
- fi
51
- if is_template "$file"; then
52
- FAILURES+=("[$rel] still contains template placeholders (e.g., <list>, <3 adjectives>)")
53
- FAILURES+=(" → Suggested fix: edit $rel to replace all <placeholder> markers with real content")
54
- return
55
- fi
56
- PASSED+=("[$rel] OK (filled in)")
57
- }
58
-
59
- check_optional_guideline() {
60
- local file="$1"
61
- local rel="${file#$ROOT/}"
62
- if [ ! -f "$file" ]; then
63
- WARNINGS+=("[$rel] optional file missing")
64
- WARNINGS+=(" → Suggested fix: copy from projects/_template/${rel#projects/$PROJECT/} if needed")
65
- return
66
- fi
67
- PASSED+=("[$rel] present")
68
- }
69
-
70
- # === Required guidelines ===
71
- check_required_guideline "$PROJECT_DIR/guidelines/voice.md"
72
- check_required_guideline "$PROJECT_DIR/guidelines/design.md"
73
- check_required_guideline "$PROJECT_DIR/guidelines/design-tokens.md"
74
- check_required_guideline "$PROJECT_DIR/guidelines/brand-book.md"
75
- check_required_guideline "$PROJECT_DIR/guidelines/messaging.md"
76
- check_required_guideline "$PROJECT_DIR/guidelines/asset-links.md"
77
-
78
- # ICPs: at least one non-template file
79
- if [ ! -d "$PROJECT_DIR/guidelines/icps" ]; then
80
- FAILURES+=("[projects/$PROJECT/guidelines/icps/] directory missing")
81
- FAILURES+=(" → Suggested fix: mkdir -p $PROJECT_DIR/guidelines/icps && cp projects/_template/guidelines/icps/_persona-template.md $PROJECT_DIR/guidelines/icps/")
82
- else
83
- ICP_COUNT=$(find "$PROJECT_DIR/guidelines/icps" -type f -name '*.md' -not -name '_persona-template.md' | wc -l)
84
- if [ "$ICP_COUNT" -eq 0 ]; then
85
- FAILURES+=("[projects/$PROJECT/guidelines/icps/] no persona file (only _persona-template.md or empty)")
86
- FAILURES+=(" → Suggested fix: cp projects/_template/guidelines/icps/_persona-template.md $PROJECT_DIR/guidelines/icps/<persona-slug>.md and fill in")
87
- else
88
- PASSED+=("[projects/$PROJECT/guidelines/icps/] $ICP_COUNT persona file(s)")
89
- fi
90
- fi
91
-
92
- # === Optional guidelines ===
93
- check_optional_guideline "$PROJECT_DIR/guidelines/do-and-dont.md"
94
- check_optional_guideline "$PROJECT_DIR/guidelines/compliance.md"
95
- check_optional_guideline "$PROJECT_DIR/guidelines/competitors.md"
96
-
97
- # === Project root files ===
98
- if [ -f "$PROJECT_DIR/CLAUDE.md" ]; then
99
- if grep -q '<Project Name>' "$PROJECT_DIR/CLAUDE.md" 2>/dev/null; then
100
- FAILURES+=("[projects/$PROJECT/CLAUDE.md] still contains <Project Name> placeholder")
101
- FAILURES+=(" → Suggested fix: edit projects/$PROJECT/CLAUDE.md and fill in identity, audience, agents")
102
- else
103
- PASSED+=("[projects/$PROJECT/CLAUDE.md] filled in")
104
- fi
105
- else
106
- FAILURES+=("[projects/$PROJECT/CLAUDE.md] missing")
107
- fi
108
-
109
- if [ -f "$PROJECT_DIR/state.md" ]; then
110
- PASSED+=("[projects/$PROJECT/state.md] present")
111
- else
112
- WARNINGS+=("[projects/$PROJECT/state.md] missing")
113
- WARNINGS+=(" → Suggested fix: cp projects/_template/state.md $PROJECT_DIR/state.md")
114
- fi
115
-
116
- # === Agent instances ===
117
- INSTANCES=()
118
- while IFS= read -r path; do
119
- INSTANCES+=("$path")
120
- done < <(find "$ROOT" -type d -path "*/projects/$PROJECT" -not -path "*/_template/*" -not -path "*/_archive/*" 2>/dev/null | grep -v "^$PROJECT_DIR$" || true)
121
-
122
- LISTED_INSTANCES=()
123
- if [ -f "$PROJECT_DIR/CLAUDE.md" ]; then
124
- while IFS= read -r line; do
125
- LISTED_INSTANCES+=("$line")
126
- done < <(grep -oE '`[a-z0-9-]+/[a-z0-9-]+/projects/[a-z0-9-]+/`' "$PROJECT_DIR/CLAUDE.md" 2>/dev/null | tr -d '`' || true)
127
- fi
128
-
129
- for inst in "${INSTANCES[@]}"; do
130
- REL="${inst#$ROOT/}"
131
-
132
- # config/default.yaml
133
- CONFIG="$inst/config/default.yaml"
134
- if [ ! -f "$CONFIG" ]; then
135
- FAILURES+=("[$REL/config/default.yaml] missing")
136
- else
137
- # Try YAML parse (use python3 if available, else just check file is non-empty)
138
- if command -v python3 >/dev/null 2>&1; then
139
- if ! python3 -c "import yaml; list(yaml.safe_load_all(open('$CONFIG')))" 2>/dev/null; then
140
- FAILURES+=("[$REL/config/default.yaml] YAML parse error")
141
- FAILURES+=(" → Suggested fix: check YAML syntax with: python3 -c 'import yaml; list(yaml.safe_load_all(open(\"$CONFIG\"))'")
142
- else
143
- # Check project field matches folder
144
- DECLARED_PROJECT=$(python3 -c "import yaml; docs = list(yaml.safe_load_all(open('$CONFIG'))); print((docs[0] or {}).get('project', ''))" 2>/dev/null || echo "")
145
- if [ "$DECLARED_PROJECT" != "$PROJECT" ]; then
146
- FAILURES+=("[$REL/config/default.yaml] project field is '$DECLARED_PROJECT', expected '$PROJECT'")
147
- FAILURES+=(" → Suggested fix: edit $REL/config/default.yaml and set 'project: $PROJECT'")
148
- else
149
- PASSED+=("[$REL/config/default.yaml] valid YAML, project matches")
150
- fi
151
- fi
152
- else
153
- PASSED+=("[$REL/config/default.yaml] present (YAML not validated, python3 missing)")
154
- fi
155
- fi
156
-
157
- # asset-references.md
158
- if [ -f "$inst/asset-references.md" ]; then
159
- PASSED+=("[$REL/asset-references.md] present")
160
- else
161
- WARNINGS+=("[$REL/asset-references.md] missing")
162
- fi
163
-
164
- # === Tool bindings: TODO required → fail; TODO optional → warn ===
165
- # Resolve agent.md from the instance path: $inst is .../<fn>/<agent>/projects/<project>
166
- INST_PARENT="$(cd "$inst/../.." && pwd)"
167
- AGENT_MD_FOR_INST="$INST_PARENT/agent.md"
168
- if [ -f "$CONFIG" ] && [ -f "$AGENT_MD_FOR_INST" ] && command -v python3 >/dev/null 2>&1; then
169
- BINDING_REPORT=$(CONFIG_PATH="$CONFIG" AGENT_MD_PATH="$AGENT_MD_FOR_INST" REL_PATH="$REL" python3 << 'PYEOF' 2>/dev/null || true
170
- import os, re, sys
171
- config_path = os.environ["CONFIG_PATH"]
172
- agent_md = os.environ["AGENT_MD_PATH"]
173
- rel = os.environ["REL_PATH"]
174
-
175
- try:
176
- import yaml
177
- except ImportError:
178
- sys.exit(0)
179
-
180
- with open(agent_md) as f:
181
- am = f.read()
182
- sm = re.search(r'## Tools and bindings.*?\n```yaml\n(.*?)\n```', am, re.DOTALL)
183
- if not sm:
184
- sys.exit(0)
185
- try:
186
- schema = yaml.safe_load(sm.group(1)) or {}
187
- except Exception:
188
- sys.exit(0)
189
-
190
- with open(config_path) as f:
191
- raw = f.read()
192
-
193
- # Walk lines inside the tools: block; capture (tool, key) pairs whose value is TODO.
194
- in_tools = False
195
- current_tool = None
196
- todos = []
197
- for line in raw.split("\n"):
198
- if re.match(r'^tools:\s*$', line):
199
- in_tools = True
200
- continue
201
- if not in_tools:
202
- continue
203
- if re.match(r'^[A-Za-z]', line):
204
- # left the tools block (back to top-level key)
205
- in_tools = False
206
- current_tool = None
207
- continue
208
- tm = re.match(r'^ ([a-z_][a-z0-9_]*):\s*$', line)
209
- if tm:
210
- current_tool = tm.group(1)
211
- continue
212
- bm = re.match(r'^ ([a-z_][a-z0-9_]*):\s*#\s*TODO\b', line)
213
- if bm and current_tool:
214
- todos.append((current_tool, bm.group(1)))
215
-
216
- for tool, key in todos:
217
- tool_schema = schema.get(tool, {}) if isinstance(schema, dict) else {}
218
- key_schema = tool_schema.get(key, {}) if isinstance(tool_schema, dict) else {}
219
- required = bool(key_schema.get("required", False)) if isinstance(key_schema, dict) else False
220
- severity = "FAIL" if required else "WARN"
221
- print(f"{severity}\t{tool}.{key}")
222
- PYEOF
223
- )
224
- while IFS=$'\t' read -r severity binding; do
225
- [ -z "$severity" ] && continue
226
- if [ "$severity" = "FAIL" ]; then
227
- FAILURES+=("[$REL/config/default.yaml] required tool binding '$binding' is TODO")
228
- FAILURES+=(" → Suggested fix: edit $REL/config/default.yaml and set tools.$binding to a real value")
229
- else
230
- WARNINGS+=("[$REL/config/default.yaml] optional tool binding '$binding' is TODO (will be skipped at runtime)")
231
- fi
232
- done <<< "$BINDING_REPORT"
233
- fi
234
-
235
- # Required directories
236
- for d in log/runs log/feedback playbook; do
237
- if [ -d "$inst/$d" ]; then
238
- PASSED+=("[$REL/$d/] present")
239
- else
240
- WARNINGS+=("[$REL/$d/] missing (will be auto-created on first run)")
241
- fi
242
- done
243
-
244
- # Is this instance listed in CLAUDE.md?
245
- EXPECTED_PATH=$(echo "$REL/" | sed 's|/projects/.*|/projects/'"$PROJECT"'/|')
246
- FOUND=0
247
- for listed in "${LISTED_INSTANCES[@]}"; do
248
- if [ "$listed" = "$EXPECTED_PATH" ]; then
249
- FOUND=1
250
- break
251
- fi
252
- done
253
- if [ $FOUND -eq 0 ]; then
254
- WARNINGS+=("[$REL] instance not listed in projects/$PROJECT/CLAUDE.md ## Active agent instances")
255
- WARNINGS+=(" → Suggested fix: add a line under '## Active agent instances' in CLAUDE.md")
256
- fi
257
- done
258
-
259
- # Listed instances that don't exist
260
- for listed in "${LISTED_INSTANCES[@]}"; do
261
- if [ ! -d "$ROOT/${listed%/}" ]; then
262
- WARNINGS+=("[$listed] listed in CLAUDE.md but folder does not exist")
263
- WARNINGS+=(" → Suggested fix: either create the instance with new-agent-instance.sh or remove the line from CLAUDE.md")
264
- fi
265
- done
266
-
267
- # === Determine status ===
268
- if [ ${#FAILURES[@]} -gt 0 ]; then
269
- STATUS="fail"
270
- elif [ ${#WARNINGS[@]} -gt 0 ]; then
271
- STATUS="warn"
272
- else
273
- STATUS="pass"
274
- fi
275
-
276
- # Count items (each FAILURE/WARNING entry is sometimes 2 lines: msg + suggested fix)
277
- # Real count is half the FAILURES/WARNINGS for entries with → Suggested fix
278
- count_items() {
279
- local arr=("$@")
280
- local n=0
281
- for item in "${arr[@]}"; do
282
- if ! [[ "$item" =~ ^[[:space:]]*→ ]]; then
283
- n=$((n+1))
284
- fi
285
- done
286
- echo $n
287
- }
288
-
289
- N_FAIL=0
290
- for item in "${FAILURES[@]:-}"; do
291
- [ -z "$item" ] && continue
292
- [[ "$item" =~ ^[[:space:]]+→ ]] && continue
293
- N_FAIL=$((N_FAIL + 1))
294
- done
295
- N_WARN=0
296
- for item in "${WARNINGS[@]:-}"; do
297
- [ -z "$item" ] && continue
298
- [[ "$item" =~ ^[[:space:]]+→ ]] && continue
299
- N_WARN=$((N_WARN + 1))
300
- done
301
- N_PASS=${#PASSED[@]}
302
-
303
- # === Write report ===
304
- {
305
- echo "---"
306
- echo "operation: audit-project"
307
- echo "project: $PROJECT"
308
- echo "ran: $TIMESTAMP"
309
- echo "status: $STATUS"
310
- echo "---"
311
- echo ""
312
- echo "# Audit: $PROJECT"
313
- echo ""
314
- echo "## Summary"
315
- echo "- $N_PASS passed"
316
- echo "- $N_WARN warnings"
317
- echo "- $N_FAIL failures"
318
- echo ""
319
- if [ $N_FAIL -gt 0 ]; then
320
- echo "## Failures"
321
- for line in "${FAILURES[@]}"; do
322
- echo "- $line"
323
- done
324
- echo ""
325
- fi
326
- if [ $N_WARN -gt 0 ]; then
327
- echo "## Warnings"
328
- for line in "${WARNINGS[@]}"; do
329
- echo "- $line"
330
- done
331
- echo ""
332
- fi
333
- if [ $N_PASS -gt 0 ]; then
334
- echo "## Passed"
335
- for line in "${PASSED[@]}"; do
336
- echo "- $line"
337
- done
338
- fi
339
- } > "$REPORT"
340
-
341
- # === Print summary ===
342
- echo "Audit: $PROJECT — $STATUS"
343
- echo " Passed: $N_PASS"
344
- echo " Warnings: $N_WARN"
345
- echo " Failures: $N_FAIL"
346
- echo ""
347
- if [ $N_FAIL -gt 0 ]; then
348
- echo "Failures:"
349
- for line in "${FAILURES[@]}"; do
350
- echo " $line"
351
- done
352
- echo ""
353
- fi
354
- if [ $N_WARN -gt 0 ] && [ $N_WARN -le 5 ]; then
355
- echo "Warnings:"
356
- for line in "${WARNINGS[@]}"; do
357
- echo " $line"
358
- done
359
- echo ""
360
- fi
361
- echo "Full report: $REPORT"
@@ -1,114 +0,0 @@
1
- #!/usr/bin/env bash
2
- # new-agent-instance.sh — adds an instance of a global agent to a project
3
- # Usage: bash scripts/new-agent-instance.sh <project> <function> <agent-name>
4
-
5
- set -euo pipefail
6
-
7
- if [ $# -ne 3 ]; then
8
- echo "Usage: $0 <project> <function> <agent-name>"
9
- echo "Example: $0 myproject gtm sdr"
10
- exit 1
11
- fi
12
-
13
- PROJECT="$1"
14
- FN="$2"
15
- AGENT="$3"
16
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
17
-
18
- source "$ROOT/scripts/lib/functions.sh"
19
-
20
- if ! is_valid_function "$FN"; then
21
- echo "ERROR: '$FN' is not a registered function." >&2
22
- echo "Registered functions:" >&2
23
- read_functions | sed 's/^/ - /' >&2
24
- exit 1
25
- fi
26
-
27
- PROJECT_DIR="$ROOT/projects/$PROJECT"
28
- GLOBAL_AGENT_DIR="$ROOT/$FN/$AGENT"
29
- INSTANCE_DIR="$GLOBAL_AGENT_DIR/projects/$PROJECT"
30
- INSTANCE_TEMPLATE="$GLOBAL_AGENT_DIR/projects/_template"
31
-
32
- if [ ! -d "$PROJECT_DIR" ]; then
33
- echo "ERROR: Project '$PROJECT' not found at $PROJECT_DIR"
34
- echo "Create it first: bash scripts/new-project.sh $PROJECT"
35
- exit 1
36
- fi
37
-
38
- if [ ! -d "$GLOBAL_AGENT_DIR" ]; then
39
- echo "ERROR: Global agent '$FN/$AGENT' not found at $GLOBAL_AGENT_DIR"
40
- echo "Create it first: bash scripts/new-agent.sh $FN $AGENT"
41
- exit 1
42
- fi
43
-
44
- if [ -d "$INSTANCE_DIR" ]; then
45
- echo "ERROR: Instance already exists at $INSTANCE_DIR"
46
- exit 1
47
- fi
48
-
49
- if [ ! -d "$INSTANCE_TEMPLATE" ]; then
50
- echo "ERROR: Agent has no _template instance at $INSTANCE_TEMPLATE"
51
- echo "(Recreate the agent or create the template manually.)"
52
- exit 1
53
- fi
54
-
55
- CURRENT_MONTH=$(date -u +"%Y-%m")
56
- TODAY=$(date -u +"%Y-%m-%d")
57
-
58
- echo "Adding instance of $FN/$AGENT to project $PROJECT"
59
-
60
- # Copy the template
61
- cp -R "$INSTANCE_TEMPLATE" "$INSTANCE_DIR"
62
-
63
- # Portable sed
64
- SED_INPLACE=(-i)
65
- if [[ "$(uname)" == "Darwin" ]]; then
66
- SED_INPLACE=(-i '')
67
- fi
68
-
69
- # Patch placeholders in config and asset-references
70
- sed "${SED_INPLACE[@]}" "s/<project-slug>/$PROJECT/g" "$INSTANCE_DIR/config/default.yaml"
71
- sed "${SED_INPLACE[@]}" "s/<YYYY-MM-DD>/$TODAY/g" "$INSTANCE_DIR/config/default.yaml"
72
- sed "${SED_INPLACE[@]}" "s/<Project>/$PROJECT/g" "$INSTANCE_DIR/config/default.yaml"
73
- sed "${SED_INPLACE[@]}" "s/<project>/$PROJECT/g" "$INSTANCE_DIR/asset-references.md"
74
-
75
- # Set up current month in log dirs
76
- mkdir -p "$INSTANCE_DIR/log/runs/$CURRENT_MONTH" "$INSTANCE_DIR/log/feedback/$CURRENT_MONTH"
77
- touch "$INSTANCE_DIR/log/runs/$CURRENT_MONTH/.gitkeep"
78
- touch "$INSTANCE_DIR/log/feedback/$CURRENT_MONTH/.gitkeep"
79
-
80
- # Prompt for tool bindings if the global agent.md has them
81
- AGENT_MD="$GLOBAL_AGENT_DIR/agent.md"
82
- INSTANCE_CONFIG="$INSTANCE_DIR/config/default.yaml"
83
- if [ -f "$AGENT_MD" ] && grep -q '^## Tools and bindings' "$AGENT_MD"; then
84
- echo ""
85
- echo "=== Tool bindings for $FN/$AGENT in $PROJECT ==="
86
- echo "Enter values for each binding. Press Enter (or type 'skip') to leave as TODO."
87
- bash "$ROOT/scripts/lib/bindings-prompt.sh" "$AGENT_MD" "$INSTANCE_CONFIG" || \
88
- echo "WARNING: bindings-prompt failed; tools: block not appended. Edit $INSTANCE_CONFIG manually."
89
- else
90
- echo ""
91
- echo "(Agent has no '## Tools and bindings' section in agent.md — skipping binding prompt)"
92
- fi
93
-
94
- # Pull list of expected MCPs and skills from agent's .mcp.json (rough — just shows what file exists)
95
- echo ""
96
- echo "✓ Instance added: $INSTANCE_DIR"
97
- echo ""
98
- echo "Reminders:"
99
- echo " - Edit $INSTANCE_DIR/config/default.yaml (see $GLOBAL_AGENT_DIR/agent.md § Inputs)"
100
- echo " - Edit $INSTANCE_DIR/asset-references.md to list which assets this agent uses"
101
- echo " - Verify project has required guidelines:"
102
- echo " $PROJECT_DIR/guidelines/voice.md"
103
- echo " $PROJECT_DIR/guidelines/icps/*.md (at least one)"
104
- echo " $PROJECT_DIR/guidelines/asset-links.md"
105
- echo " - Verify agent's MCPs are configured in $GLOBAL_AGENT_DIR/.mcp.json"
106
- echo ""
107
- echo "Test from a session:"
108
- echo " cd $INSTANCE_DIR/"
109
- echo " claude"
110
- echo " \"Run $AGENT — dry run, just show me the plan\""
111
- echo ""
112
- # Scheduling: register with the native desktop scheduler via `roster schedule install`.
113
- # See docs/SCHEDULING.md and docs/adr/0001-scheduling-architecture.md for the model.
114
- echo "Optionally schedule this agent: roster schedule install $FN/$AGENT <plan> --cron \"<expr>\" --tool claude|codex"
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env bash
2
- # new-project.sh — scaffold a new project substrate inside a roster workspace.
3
- #
4
- # Usage:
5
- # bash scripts/new-project.sh <project-name> [<function>]
6
- #
7
- # Arguments:
8
- # project-name Free-form name. Normalized to kebab-case (lowercase,
9
- # [a-z0-9-], non-alphanumeric runs collapsed to '-').
10
- # Examples:
11
- # "My Co" -> my-co
12
- # "foo bar/baz" -> foo-bar-baz
13
- # "Acme Corp 2" -> acme-corp-2
14
- # function Optional. If provided, must be registered in
15
- # .config/functions.yaml (gtm, product, design, ops, ...).
16
- #
17
- # Creates:
18
- # projects/<slug>/
19
- # guidelines/.gitkeep
20
- # config/default.yaml (project-level config skeleton)
21
- # state.md (frontmatter + 5-line stub)
22
- #
23
- # Exit codes:
24
- # 0 success
25
- # 1 usage / validation error
26
-
27
- set -euo pipefail
28
-
29
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
30
- # shellcheck disable=SC1091
31
- source "$ROOT/scripts/lib/functions.sh"
32
-
33
- usage() {
34
- echo "Usage: $0 <project-name> [<function>]" >&2
35
- echo " project-name Free-form; normalized to kebab-case" >&2
36
- echo " function Optional; must be in .config/functions.yaml" >&2
37
- }
38
-
39
- if [ $# -lt 1 ] || [ $# -gt 2 ]; then
40
- usage
41
- exit 1
42
- fi
43
-
44
- RAW_NAME="$1"
45
- FUNCTION="${2:-}"
46
-
47
- normalize() {
48
- # 1. lowercase
49
- # 2. replace any run of non-alphanumeric chars with a single '-'
50
- # 3. trim leading/trailing '-'
51
- printf '%s' "$1" \
52
- | tr '[:upper:]' '[:lower:]' \
53
- | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//'
54
- }
55
-
56
- SLUG="$(normalize "$RAW_NAME")"
57
-
58
- if [ -z "$SLUG" ]; then
59
- echo "ERROR: project name '$RAW_NAME' is empty after normalization" >&2
60
- exit 1
61
- fi
62
-
63
- if ! [[ "$SLUG" =~ ^[a-z][a-z0-9-]*$ ]]; then
64
- echo "ERROR: normalized slug '$SLUG' must start with a letter and contain only a-z, 0-9, '-'" >&2
65
- exit 1
66
- fi
67
-
68
- if [ -n "$FUNCTION" ]; then
69
- if ! is_valid_function "$FUNCTION"; then
70
- echo "ERROR: function '$FUNCTION' is not registered in .config/functions.yaml" >&2
71
- echo "Registered functions:" >&2
72
- read_functions 2>/dev/null | sed 's/^/ - /' >&2 || echo " (registry empty or missing)" >&2
73
- exit 1
74
- fi
75
- fi
76
-
77
- TARGET="$ROOT/projects/$SLUG"
78
-
79
- if [ -e "$TARGET" ]; then
80
- echo "ERROR: project '$SLUG' already exists at $TARGET" >&2
81
- exit 1
82
- fi
83
-
84
- TIMESTAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
85
-
86
- mkdir -p "$TARGET/guidelines" "$TARGET/config" "$TARGET/assets"
87
- touch "$TARGET/guidelines/.gitkeep" "$TARGET/assets/.gitkeep"
88
-
89
- cat >"$TARGET/config/default.yaml" <<EOF
90
- ---
91
- project: $SLUG
92
- created: ${TIMESTAMP%T*}
93
- ---
94
-
95
- # Project-level config for $SLUG.
96
- # Cross-agent defaults. Agent-scoped instance config lives at:
97
- # <function>/<agent>/projects/$SLUG/config/default.yaml
98
-
99
- display_name: $SLUG
100
- stage: early
101
- motion: outbound
102
- approval_channel: auto
103
- EOF
104
-
105
- cat >"$TARGET/state.md" <<EOF
106
- ---
107
- updated: $TIMESTAMP
108
- ---
109
-
110
- Last task: (none yet)
111
- Active artifacts: (none)
112
- Open questions: (none)
113
- Next session: fill in guidelines/voice.md and at least one ICP
114
- Notes: created via scripts/new-project.sh
115
- EOF
116
-
117
- echo "✓ Project '$SLUG' created at projects/$SLUG/"
118
- echo ""
119
- echo "Next steps:"
120
- echo " 1. Fill projects/$SLUG/guidelines/voice.md (3 adjectives + tone)"
121
- echo " 2. Add at least one ICP under projects/$SLUG/guidelines/icps/"
122
- echo " 3. Edit projects/$SLUG/config/default.yaml — set display_name, stage, motion"
123
- if [ -n "$FUNCTION" ]; then
124
- echo " 4. Wire an agent instance via chief-of-staff: add-agent-to-project project=$SLUG function=$FUNCTION agent=<name>"
125
- fi
@@ -1,67 +0,0 @@
1
- #!/usr/bin/env bash
2
- # remove-agent-from-project.sh — archives a single agent instance from a project
3
- # Usage: bash scripts/remove-agent-from-project.sh <project> <function> <agent>
4
-
5
- set -euo pipefail
6
-
7
- if [ $# -ne 3 ]; then
8
- echo "Usage: $0 <project> <function> <agent>"
9
- exit 1
10
- fi
11
-
12
- PROJECT="$1"
13
- FN="$2"
14
- AGENT="$3"
15
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
16
- INSTANCE_DIR="$ROOT/$FN/$AGENT/projects/$PROJECT"
17
-
18
- if [ ! -d "$INSTANCE_DIR" ]; then
19
- echo "ERROR: Instance not found at $INSTANCE_DIR"
20
- exit 1
21
- fi
22
-
23
- DATE=$(date +%Y-%m-%d)
24
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
25
-
26
- # Determine archive suffix
27
- SUFFIX="$DATE"
28
- COUNTER=2
29
- while [ -d "$ROOT/_archive/$FN/$AGENT/projects/$PROJECT-$SUFFIX" ]; do
30
- SUFFIX="$DATE-$COUNTER"
31
- COUNTER=$((COUNTER + 1))
32
- done
33
-
34
- echo "Removing instance: $FN/$AGENT/projects/$PROJECT (archiving with suffix $SUFFIX)"
35
-
36
- mkdir -p "$ROOT/_archive/$FN/$AGENT/projects"
37
- mv "$INSTANCE_DIR" "$ROOT/_archive/$FN/$AGENT/projects/$PROJECT-$SUFFIX"
38
- echo " Moved: $FN/$AGENT/projects/$PROJECT/ → _archive/$FN/$AGENT/projects/$PROJECT-$SUFFIX/"
39
-
40
- # Update project CLAUDE.md — remove the line referencing this instance
41
- PROJECT_CLAUDE="$ROOT/projects/$PROJECT/CLAUDE.md"
42
- if [ -f "$PROJECT_CLAUDE" ]; then
43
- # Remove lines that reference the removed instance under "Active agent instances"
44
- # Match patterns like "- `gtm/sdr/projects/<project>/` — ..."
45
- SED_INPLACE=(-i)
46
- if [[ "$(uname)" == "Darwin" ]]; then
47
- SED_INPLACE=(-i '')
48
- fi
49
- sed "${SED_INPLACE[@]}" "/^- \`$FN\/$AGENT\/projects\/$PROJECT\//d" "$PROJECT_CLAUDE"
50
- echo " Updated: projects/$PROJECT/CLAUDE.md (removed instance line)"
51
- fi
52
-
53
- # Operation log
54
- LOG_DIR="$ROOT/chief-of-staff/logs/$(date +%Y-%m)"
55
- mkdir -p "$LOG_DIR"
56
- LOG_FILE="$LOG_DIR/operations-$(date +%Y-%m-%d).md"
57
- {
58
- echo ""
59
- echo "## $TIMESTAMP — remove-agent-from-project"
60
- echo "Project: $PROJECT, Agent: $FN/$AGENT"
61
- echo "Archive suffix: $SUFFIX"
62
- } >> "$LOG_FILE"
63
-
64
- echo ""
65
- echo "✓ Instance removed (archived)."
66
- echo " To restore: move _archive/$FN/$AGENT/projects/$PROJECT-$SUFFIX back to $FN/$AGENT/projects/$PROJECT"
67
- echo " Operation log: $LOG_FILE"