@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,136 +1,55 @@
1
1
  #!/usr/bin/env bash
2
- # bindings-prompt.sh — read ## Tools and bindings from agent.md, prompt user, append YAML
2
+ # bindings-prompt.sh — DISABLED in v1.0 (ROS-78).
3
3
  #
4
- # Args:
5
- # $1 = path to agent.md (the global agent contract)
6
- # $2 = path to instance config/default.yaml (will append tools: block)
4
+ # Pre-v1.0 behavior: read `## Tools and bindings` from agent.md (legacy
5
+ # two-level `tool: key: {required, description}` schema), prompt the user
6
+ # for binding values, and append a `tools:` block to a project-instance
7
+ # config at `projects/<inst>/config/default.yaml`.
7
8
  #
8
- # Behavior:
9
- # 1. Extract YAML block from `## Tools and bindings` in agent.md
10
- # 2. For each tool/key, prompt user via /dev/tty for value (showing required/optional + description)
11
- # 3. Empty input or "skip" write `# TODO: <description>` placeholder
12
- # 4. Append a `tools:` block to the instance config
9
+ # Both inputs change in v1.0:
10
+ # 1. The shipped `## Tools and bindings` block in agent.md is now a flat
11
+ # schema (`tool: { env_var, required, description }` per
12
+ # conventions.md). The legacy parser silently emits an empty
13
+ # `tools.<tool>:` block when it encounters scalar values where it
14
+ # expects a mapping.
15
+ # 2. The instance-config target is gone — agent config lives at
16
+ # `<function>/<agent>/config.yaml`, and env-var values belong in
17
+ # workspace `/.env` (overridable in `<agent>/.env`).
13
18
  #
14
- # Non-TTY environments fall back to TODO placeholders for every binding.
19
+ # The proper v1.0 flow (read agent.md flat schema write metadata to
20
+ # config.yaml `tools:` block → prompt for required env-var values and
21
+ # append to `/.env`) requires the env-merge loader that ships in Phase 2.
22
+ # Rather than ship a script whose advertised behavior is broken against
23
+ # the new schema, this script aborts with manual-configuration instructions
24
+ # (edit agent.md schema → mirror to config.yaml → fill /.env).
25
+ #
26
+ # Tracking: re-enable as part of the Phase 2 cli-plumbing reshape
27
+ # (env-merge loader + doctor checks 13-15).
15
28
 
16
29
  set -euo pipefail
17
30
 
18
- AGENT_MD="${1:-}"
19
- INSTANCE_CONFIG="${2:-}"
20
-
21
- if [ -z "$AGENT_MD" ] || [ -z "$INSTANCE_CONFIG" ]; then
22
- echo "Usage: $0 <agent.md> <instance-config/default.yaml>" >&2
23
- exit 1
24
- fi
25
-
26
- if [ ! -f "$AGENT_MD" ]; then
27
- echo "ERROR: agent.md not found at $AGENT_MD" >&2
28
- exit 1
29
- fi
30
- if [ ! -f "$INSTANCE_CONFIG" ]; then
31
- echo "ERROR: instance config not found at $INSTANCE_CONFIG" >&2
32
- exit 1
33
- fi
34
-
35
- if ! command -v python3 >/dev/null 2>&1; then
36
- echo "ERROR: python3 is required for bindings-prompt.sh" >&2
37
- exit 1
38
- fi
39
-
40
- # Drive prompts + YAML emission via python; pass file paths via env to avoid quoting hell.
41
- export AGENT_MD INSTANCE_CONFIG
42
-
43
- FINAL_YAML=$(python3 << 'PYEOF'
44
- import os, re, sys
45
-
46
- agent_md = os.environ["AGENT_MD"]
47
- with open(agent_md) as f:
48
- content = f.read()
49
-
50
- m = re.search(r'## Tools and bindings.*?\n```yaml\n(.*?)\n```', content, re.DOTALL)
51
- if not m:
52
- sys.stderr.write(f"ERROR: no '## Tools and bindings' YAML block in {agent_md}\n")
53
- sys.exit(1)
54
-
55
- schema_text = m.group(1)
56
-
57
- try:
58
- import yaml
59
- except ImportError:
60
- sys.stderr.write("ERROR: pyyaml required (pip3 install --user pyyaml)\n")
61
- sys.exit(1)
62
-
63
- try:
64
- schema = yaml.safe_load(schema_text)
65
- except Exception as e:
66
- sys.stderr.write(f"ERROR parsing bindings schema: {e}\n")
67
- sys.exit(1)
68
-
69
- if not isinstance(schema, dict):
70
- sys.stderr.write("Bindings schema is not a YAML mapping\n")
71
- sys.exit(1)
72
-
73
- # Try to open /dev/tty for interactive input. Fall back to all-TODO if unavailable.
74
- try:
75
- tty = open("/dev/tty", "r")
76
- interactive = True
77
- except OSError:
78
- tty = None
79
- interactive = False
80
- sys.stderr.write("(non-interactive environment — all bindings will be TODO placeholders)\n")
81
-
82
- def yaml_quote(value: str) -> str:
83
- if value == "":
84
- return '""'
85
- if any(c in value for c in [":", "#", "@", "{", "}", "[", "]", ",", "&", "*", "!", "|", ">", "'", '"', "%", "`"]):
86
- escaped = value.replace('\\', '\\\\').replace('"', '\\"')
87
- return f'"{escaped}"'
88
- return value
89
-
90
- out_lines = []
91
- out_lines.append("")
92
- out_lines.append("# Tool bindings (filled via chief-of-staff scaffolding prompt)")
93
- out_lines.append("tools:")
94
-
95
- for tool, bindings in schema.items():
96
- if not isinstance(bindings, dict):
97
- continue
98
- out_lines.append(f" {tool}:")
99
- for key, meta in bindings.items():
100
- if not isinstance(meta, dict):
101
- continue
102
- required = bool(meta.get("required", False))
103
- description = str(meta.get("description", "") or "")
104
- marker = "(required)" if required else "(optional)"
105
-
106
- value = ""
107
- if interactive:
108
- sys.stderr.write(f"\n {tool}.{key} {marker}\n")
109
- sys.stderr.write(f" {description}\n")
110
- sys.stderr.write(f" > ")
111
- sys.stderr.flush()
112
- try:
113
- value = tty.readline().strip()
114
- except (OSError, KeyboardInterrupt):
115
- value = ""
31
+ cat >&2 <<'MSG'
32
+ bindings-prompt.sh is disabled in Roster v1.0.
116
33
 
117
- if value == "" or value.lower() == "skip":
118
- out_lines.append(f" {key}: # TODO: {description}")
119
- else:
120
- out_lines.append(f" {key}: {yaml_quote(value)}")
34
+ The legacy two-level schema parser this script uses is incompatible with
35
+ the flat ## Tools and bindings schema documented in conventions.md
36
+ ("Tool bindings" section). The Phase 2 reshape (env-merge loader +
37
+ config.yaml/.env split) will rebuild this flow.
121
38
 
122
- print("\n".join(out_lines))
39
+ Configure tool bindings by hand (the env-merge loader reads them at
40
+ runtime — what's missing is the auto-mirroring generator this script
41
+ was meant to provide):
123
42
 
124
- if tty is not None:
125
- tty.close()
126
- PYEOF
127
- )
43
+ 1. Open <function>/<agent>/agent.md and confirm the ## Tools and
44
+ bindings YAML block lists each tool with env_var, required, and
45
+ description fields (see conventions.md § "Tool bindings").
46
+ 2. Mirror that block as the tools: mapping in
47
+ <function>/<agent>/config.yaml.
48
+ 3. Add the corresponding env var values to workspace /.env (or, for
49
+ agent-scoped overrides, <function>/<agent>/.env).
128
50
 
129
- # Append to instance config
130
- {
131
- echo ""
132
- echo "$FINAL_YAML"
133
- } >> "$INSTANCE_CONFIG"
51
+ (The chief-of-staff guided create-agent flow shipped in v0.4 is also on
52
+ the pre-v1 shape; it will be updated alongside the env-merge loader.)
53
+ MSG
134
54
 
135
- echo "" >&2
136
- echo "✓ Tool bindings appended to $INSTANCE_CONFIG" >&2
55
+ exit 2
@@ -62,7 +62,7 @@ description: "$fn agent — TODO: fill in description"
62
62
 
63
63
  # /$name
64
64
 
65
- You are operating the \`$fn/$name\` agent. Load \`$fn/$name/agent.md\` and the project's relevant context.
65
+ You are operating the \`$fn/$name\` agent. Load \`$fn/$name/agent.md\` and the workspace's relevant context.
66
66
 
67
67
  The user request is: \$ARGUMENTS
68
68
 
@@ -70,28 +70,25 @@ The user request is: \$ARGUMENTS
70
70
 
71
71
  Parse the user request:
72
72
 
73
- 1. **If it matches \`run <plan-name> for <project>\` or \`run <plan-name> on <project>\`**:
73
+ 1. **If it matches \`run <plan-name>\`**:
74
74
  - Load \`$fn/$name/plans/<plan-name>.yaml\`. If it doesn't exist, list available plans and ask user to pick.
75
- - Load \`projects/<project>/CLAUDE.md\` and relevant guidelines.
76
- - Load \`$fn/$name/projects/<project>/config/default.yaml\`.
77
- - Validate that all required tool bindings are non-TODO. Abort if not.
78
- - Execute the plan steps. Substitute \`\${tools.X.Y}\`, \`\${inputs.X}\`, \`\${config.X}\`.
79
- - Log to \`$fn/$name/projects/<project>/log/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\`.
80
- - Surface HITL approvals per the plan's approval_channel.
81
-
82
- 2. **If only a project is named (no plan)**:
75
+ - Load \`$fn/$name/config.yaml\` and resolve env via \`resolveAgentEnv\` (\`$fn/$name/.env\` overrides workspace \`/.env\`).
76
+ - Load workspace guidelines referenced under \`config.yaml\` \`guideline_refs:\` (e.g., \`/guidelines/voice.md\`, \`/guidelines/icps/\`, \`/guidelines/messaging.md\`).
77
+ - Validate that all required tool bindings have non-empty env vars. Abort with a clear message if not.
78
+ - Execute the plan steps. Substitute \`\${tools.X.env_var}\`, \`\${inputs.X}\`, \`\${config.X}\`.
79
+ - Log to \`$fn/$name/logs/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\`.
80
+ - Surface HITL approvals per the plan's \`approval_channel\`.
81
+
82
+ 2. **If no plan is named**:
83
83
  - List available plans from \`$fn/$name/plans/\` with descriptions. Ask user to pick.
84
84
 
85
- 3. **If neither plan nor project is named**:
86
- - List available projects and plans. Ask user to specify both.
87
-
88
- 4. **For ad-hoc strategic work**: suggest invoking \`$fn/EXPERT.md\` instead.
85
+ 3. **For ad-hoc strategic work**: suggest invoking \`$fn/EXPERT.md\` instead.
89
86
 
90
87
  ## Constraints
91
88
 
92
89
  - Only run plans that exist as files in \`$fn/$name/plans/\`.
93
90
  - Don't bypass approval gates.
94
- - File writes go to the instance's \`log/runs/\` unless the plan explicitly writes elsewhere.
91
+ - File writes go to \`$fn/$name/logs/runs/\` unless the plan explicitly writes elsewhere.
95
92
  EOF
96
93
  }
97
94
 
@@ -137,7 +134,7 @@ fi
137
134
 
138
135
  echo "Creating agent: $FN/$NAME"
139
136
 
140
- mkdir -p "$TARGET"/{subagents,playbook,logs,projects/_template,.claude/skills,.claude/plugins}
137
+ mkdir -p "$TARGET"/{subagents,playbook,pending,logs/runs,logs/feedback,.claude/skills,.claude/plugins}
141
138
 
142
139
  # agent.md stub
143
140
  cat > "$TARGET/agent.md" << EOF
@@ -149,45 +146,36 @@ cat > "$TARGET/agent.md" << EOF
149
146
 
150
147
  ## Inputs
151
148
 
152
- The orchestrator expects:
153
-
154
- - \`project\`: project slug
155
- - <other inputs>
149
+ The orchestrator expects per-plan inputs (declared in each plan's \`inputs:\` block).
156
150
 
157
151
  Read at runtime:
158
152
 
159
153
  - \`agent.md\` (this file)
160
- - \`projects/<project>/<this-agent>/config/default.yaml\`
161
- - \`projects/<project>/CLAUDE.md\`
162
- - \`projects/<project>/guidelines/voice.md\`
163
- - <other guidelines this agent uses>
164
- - \`<this-agent>/projects/<project>/playbook/\` — project-scoped lessons
165
- - \`<this-agent>/playbook/\` — global lessons
154
+ - \`config.yaml\` (workspace-root-relative guideline refs + tool bindings)
155
+ - Workspace guidelines referenced under \`config.yaml\` \`guideline_refs:\` (e.g., \`/guidelines/voice.md\`, \`/guidelines/icps/\`, \`/guidelines/messaging.md\`)
156
+ - \`playbook/\` — validated lessons (single playbook per agent)
166
157
 
167
- ## Steps
158
+ Env resolution: \`<this-agent>/.env\` overrides workspace \`/.env\`. Required tool env vars validated before the plan runs.
168
159
 
169
- 1. Resolve config and context
170
- 2. <step>
171
- 3. <step>
160
+ ## Plans
172
161
 
173
- ## Subagents
162
+ Named plans this agent runs (files in \`plans/<plan>.yaml\`). One-line description per plan.
163
+ No default plan — invoking without a plan triggers an interactive "which plan?" prompt.
174
164
 
175
- - <subagent-name>.md <one-liner>
165
+ - <plan-name>: <one-liner>
176
166
 
177
- ## Tools
178
-
179
- Agent-scoped MCPs at \`<this-agent>/.mcp.json\`:
180
- - <tool/MCP> — <purpose>
167
+ ## Subagents
181
168
 
182
- Universal MCPs (Slack, Google Drive) inherited from agent-team root.
169
+ - <subagent-name>.md <one-liner>
183
170
 
184
171
  ## Outputs
185
172
 
186
- Run file at \`projects/<project>/<this-agent>/log/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\`. See \`conventions.md\` § "Run file format".
173
+ Run file at \`logs/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\`. See \`conventions.md\` § "Run file format".
174
+ Per-plan output schemas live in each plan's \`outputs:\` block.
187
175
 
188
176
  ## Approval
189
177
 
190
- \`approval_channel: auto\` — in-session if interactive, Slack \`#${FN}\` if cron (resolved via \`SLACK_HITL_CHANNEL_$(echo "$FN" | tr '[:lower:]-' '[:upper:]_')\` in \`.env\`).
178
+ \`approval_channel: auto\` — in-session if interactive, Slack \`#${FN}\` if cron (resolved via \`SLACK_HITL_CHANNEL_$(echo "$FN" | tr '[:lower:]-' '[:upper:]_')\` in workspace \`/.env\`).
191
179
 
192
180
  ## Lessons protocol
193
181
 
@@ -206,39 +194,49 @@ cat > "$TARGET/README.md" << EOF
206
194
 
207
195
  ## Files
208
196
 
209
- - \`agent.md\` — orchestrator contract
197
+ - \`agent.md\` — orchestrator contract (behavioral prompt, plans list, tool bindings schema)
198
+ - \`config.yaml\` — guideline refs + tool bindings (workspace-root paths)
199
+ - \`.env\` — agent-scoped env overrides (gitignored, 0600 — optional, inherits from workspace \`/.env\`)
200
+ - \`plans/\` — named workflows (\`<plan>.yaml\`)
210
201
  - \`subagents/\` — specialized roles
211
- - \`playbook/\` — global lessons (one file per lesson)
212
- - \`logs/\` — agent-level operational logs
213
- - \`.claude/\` — agent-scoped skills, plugins
214
- - \`.mcp.json\` — agent-scoped MCPs (CREATE THIS see template comment)
215
- - \`projects/\` — per-project instances
202
+ - \`playbook/\` — validated lessons (single playbook per agent)
203
+ - \`pending/\` — HITL items awaiting approval
204
+ - \`logs/runs/\`, \`logs/feedback/\` — run outputs + mirrored feedback
205
+ - \`asset-references.md\` — which workspace assets this agent uses (thin pointer)
206
+ - \`.claude/\` — agent-scoped Claude Code config (skills, plugins, settings)
207
+ - \`.mcp.json\` — agent-scoped MCPs
216
208
 
217
209
  ## Invocation
218
210
 
219
- From a project instance session:
211
+ From the workspace root:
220
212
 
221
213
  \`\`\`bash
222
- cd $FN/$NAME/projects/<project>/
223
214
  claude
224
- "Run $NAME on <inputs>"
215
+ > /$NAME run <plan-name>
225
216
  \`\`\`
226
217
 
227
- From cron: see ROS-39 (Phase 2.5 scheduling primitives — wrapper layout + install script land then).
218
+ Or via natural language:
219
+
220
+ \`\`\`
221
+ "Run $FN/$NAME using the <plan-name> plan"
222
+ \`\`\`
223
+
224
+ From cron: see ADR-0001 (subscription-billed scheduling via native local schedulers). Install via \`roster schedule install $FN/$NAME <plan> --cron "<expr>" --tool claude|codex\`.
228
225
 
229
226
  ## Configuration
230
227
 
231
- Per-project: \`projects/<proj>/$FN/$NAME/config/default.yaml\` (created by \`new-agent-instance.sh\`).
228
+ \`config.yaml\` (this agent) — guideline refs + tool bindings.
229
+ Workspace \`/.env\` (root) + optional \`<this-agent>/.env\` for agent-scoped overrides.
232
230
 
233
231
  ## Outputs
234
232
 
235
- \`projects/<proj>/$FN/$NAME/log/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\`
233
+ \`logs/runs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md\` — one file per invocation.
236
234
  EOF
237
235
 
238
236
  # .mcp.json stub
239
237
  cat > "$TARGET/.mcp.json" << EOF
240
238
  {
241
- "_comment": "Agent-scoped MCPs for $NAME. Available when working in this agent's tree (including project instances). Add MCPs this agent specifically needs. Universal MCPs (Slack, Google Drive) are inherited from agent-team/.mcp.json.",
239
+ "_comment": "Agent-scoped MCPs for $NAME. Available when working in this agent's tree. Add MCPs this agent specifically needs. Universal MCPs (Slack, Google Drive) are inherited from the workspace .mcp.json.",
242
240
  "mcpServers": {}
243
241
  }
244
242
  EOF
@@ -273,41 +271,50 @@ cat > "$TARGET/subagents/_template.md" << 'EOF'
273
271
  <Specific criteria for acceptable output.>
274
272
  EOF
275
273
 
276
- # Project instance template
277
- mkdir -p "$TARGET/projects/_template/config"
278
- mkdir -p "$TARGET/projects/_template/playbook"
279
- mkdir -p "$TARGET/projects/_template/log/runs"
280
- mkdir -p "$TARGET/projects/_template/log/feedback"
281
-
282
- cat > "$TARGET/projects/_template/config/default.yaml" << EOF
283
- ---
284
- agent: $NAME
285
- project: <project-slug>
286
- created: <YYYY-MM-DD>
287
- last_modified: <YYYY-MM-DD>
288
- ---
289
-
290
- # $NAME Config — <Project>
291
-
292
- # See $FN/$NAME/agent.md § "Inputs" for required fields.
293
- # Use prose comments to explain "why" alongside "what".
274
+ # config.yaml agent config (guideline refs + tool bindings)
275
+ # Minimal stub. The env-merge loader (resolveAgentEnv) reads bindings
276
+ # from this file's tools: block, with env-var values sourced from
277
+ # workspace /.env (or this agent's .env override). Until the dialogue-
278
+ # driven generator that auto-mirrors agent.md → config.yaml ships,
279
+ # copy the ## Tools and bindings YAML block from agent.md into the
280
+ # tools: mapping below by hand.
281
+ cat > "$TARGET/config.yaml" << EOF
282
+ agent: $FN/$NAME
283
+ plans_dir: ./plans/
284
+
285
+ # Workspace-root-relative refs. Loader rejects literal absolute fs paths
286
+ # like /Users/, /home/, /etc/, /var/, /tmp/, /opt/.
287
+ guideline_refs:
288
+ voice: /guidelines/voice.md
289
+ icps: /guidelines/icps/
290
+ messaging: /guidelines/messaging.md
291
+ # add more as needed:
292
+ # brand_book: /guidelines/brand-book.md
293
+ # do_and_dont: /guidelines/do-and-dont.md
294
+ # compliance: /guidelines/compliance.md
295
+ # competitors: /guidelines/competitors.md
296
+
297
+ # Tool bindings. Each tool entry names the env var, required flag, and a
298
+ # short description. Env vars themselves live in workspace /.env (or are
299
+ # overridden in this agent's .env).
300
+ tools: {}
294
301
  EOF
295
302
 
296
- cat > "$TARGET/projects/_template/asset-references.md" << EOF
297
- # Asset references $NAME / <project>
303
+ # asset-references.md thin pointer at agent root
304
+ cat > "$TARGET/asset-references.md" << EOF
305
+ # Asset references — $FN/$NAME
298
306
 
299
- This agent uses these assets from \`projects/<project>/guidelines/asset-links.md\`:
307
+ This agent uses these assets from \`guidelines/asset-links.md\`:
300
308
 
301
309
  - <e.g., specific asset by name>
302
310
  EOF
303
311
 
304
312
  touch "$TARGET/playbook/.gitkeep"
305
- touch "$TARGET/logs/.gitkeep"
313
+ touch "$TARGET/pending/.gitkeep"
314
+ touch "$TARGET/logs/runs/.gitkeep"
315
+ touch "$TARGET/logs/feedback/.gitkeep"
306
316
  touch "$TARGET/.claude/skills/.gitkeep"
307
317
  touch "$TARGET/.claude/plugins/.gitkeep"
308
- touch "$TARGET/projects/_template/playbook/.gitkeep"
309
- touch "$TARGET/projects/_template/log/runs/.gitkeep"
310
- touch "$TARGET/projects/_template/log/feedback/.gitkeep"
311
318
 
312
319
  # === Tool bindings prompt (added by tool-bindings workflow) ===
313
320
  # Ask the user whether to define tools now. If yes, collect tool names and scaffold
@@ -346,24 +353,25 @@ if [ -t 0 ] && [ "${AGENT_TEAM_NO_CONFIRM:-0}" != "1" ]; then
346
353
  echo ""
347
354
  echo "## Tools and bindings"
348
355
  echo ""
349
- echo "Per-project tool bindings expected by this agent. Chief-of-staff prompts for these when scaffolding a new agent-instance. Values land in \`projects/<project>/config/default.yaml\` under a \`tools:\` key."
356
+ echo "Tool bindings expected by this agent. The env-merge loader reads these from \`<agent>/config.yaml\` (under a \`tools:\` key), with env-var values from workspace \`/.env\` (overridable in \`<agent>/.env\`). For now, mirror the YAML block below into \`config.yaml\` by hand the auto-mirroring generator that would derive it from this section is not yet shipped."
350
357
  echo ""
351
- echo "Fill in each tool's bindings below. Schema: each binding has a \`required\` flag (true/false) and a \`description\`."
358
+ echo "Fill in each tool's bindings below. Schema per conventions.md § \"Tool bindings\": each tool has a \`env_var\` (the env-var name the runtime reads), a \`required\` flag (true/false), and a one-line \`description\`."
352
359
  echo ""
353
360
  echo '```yaml'
354
361
  for tool in "${TOOL_NAMES[@]}"; do
362
+ tool_env=$(echo "$tool" | tr '[:lower:]-' '[:upper:]_')
355
363
  echo "$tool:"
356
- echo " # TODO: define bindings"
357
- echo " # <binding_name>:"
358
- echo " # required: true"
359
- echo " # description: \"...\""
364
+ echo " env_var: ${tool_env}_API_KEY # TODO: confirm env var name"
365
+ echo " required: true # TODO: confirm required vs optional"
366
+ echo " description: \"\" # TODO: one-line description"
360
367
  done
361
368
  echo '```'
362
369
  } >> "$NEW_AGENT_MD"
363
370
 
364
371
  echo ""
365
372
  echo "✓ Added '## Tools and bindings' to $NEW_AGENT_MD with stubs for: ${TOOL_NAMES[*]}"
366
- echo " Edit agent.md to fill in actual bindings before adding instances."
373
+ echo " Edit agent.md to fill in env_var names + descriptions, then mirror the tools: block into <agent>/config.yaml by hand."
374
+ echo " (The env-merge loader reads bindings from <agent>/config.yaml at runtime; the auto-mirroring generator that would copy this block for you is not yet shipped, so this step is manual.)"
367
375
  else
368
376
  echo " No valid tool names provided. Skipping section."
369
377
  fi
@@ -399,12 +407,12 @@ echo ""
399
407
  echo "✓ Agent '$FN/$NAME' created at $TARGET"
400
408
  echo ""
401
409
  echo "Next steps:"
402
- echo " 1. Fill in $TARGET/agent.md (purpose, inputs, steps, subagents, tools, outputs)"
403
- echo " 2. Add subagents: cp $TARGET/subagents/_template.md $TARGET/subagents/<name>.md and fill in"
404
- echo " 3. Add agent-scoped MCPs to $TARGET/.mcp.json if needed (HeyReach, Apollo, etc.)"
405
- echo " 4. Update $TARGET/README.md with a real description"
406
- echo " 5. Add at least one plan to $TARGET/plans/ (e.g., $TARGET/plans/<plan-name>.yaml)"
407
- echo " 6. Edit .claude/commands/$NAME.md to fill in the description"
408
- echo " 7. Add an instance to a project: bash scripts/new-agent-instance.sh <project> $FN $NAME"
410
+ echo " 1. Fill in $TARGET/agent.md (purpose, inputs, plans, subagents, tools, outputs)"
411
+ echo " 2. Fill in $TARGET/config.yaml (guideline_refs, tools)"
412
+ echo " 3. Add subagents: cp $TARGET/subagents/_template.md $TARGET/subagents/<name>.md and fill in"
413
+ echo " 4. Add agent-scoped MCPs to $TARGET/.mcp.json if needed (HeyReach, Apollo, etc.)"
414
+ echo " 5. Update $TARGET/README.md with a real description"
415
+ echo " 6. Add at least one plan to $TARGET/plans/ (e.g., $TARGET/plans/<plan-name>.yaml)"
416
+ echo " 7. Edit .claude/commands/$NAME.md to fill in the description"
409
417
  echo ""
410
418
  echo "Reference: see gtm/sdr/ for a complete example."
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env bash
2
+ # rename-agent.sh — renames a global agent everywhere it appears
3
+ # Usage: bash scripts/rename-agent.sh <function> <old> <new>
4
+
5
+ set -euo pipefail
6
+
7
+ if [ $# -ne 3 ]; then
8
+ echo "Usage: $0 <function> <old> <new>"
9
+ exit 1
10
+ fi
11
+
12
+ FN="$1"
13
+ OLD="$2"
14
+ NEW="$3"
15
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
16
+
17
+ if ! [[ "$NEW" =~ ^[a-z][a-z0-9-]*$ ]]; then
18
+ echo "ERROR: New slug must be lowercase, alphanumeric + hyphens, starting with a letter."
19
+ exit 1
20
+ fi
21
+
22
+ OLD_DIR="$ROOT/$FN/$OLD"
23
+ NEW_DIR="$ROOT/$FN/$NEW"
24
+
25
+ if [ ! -d "$OLD_DIR" ]; then
26
+ echo "ERROR: Agent '$FN/$OLD' not found at $OLD_DIR"
27
+ exit 1
28
+ fi
29
+
30
+ if [ -d "$NEW_DIR" ]; then
31
+ echo "ERROR: Agent '$FN/$NEW' already exists at $NEW_DIR"
32
+ exit 1
33
+ fi
34
+
35
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
36
+
37
+ mv "$OLD_DIR" "$NEW_DIR"
38
+ echo " Moved: $FN/$OLD/ → $FN/$NEW/"
39
+
40
+ SED_INPLACE=(-i)
41
+ if [[ "$(uname)" == "Darwin" ]]; then
42
+ SED_INPLACE=(-i '')
43
+ fi
44
+
45
+ # Broad replace on prose files only — these are markdown stubs where the
46
+ # old slug appears in headings / paths and we want every reference updated.
47
+ for f in "$NEW_DIR"/agent.md "$NEW_DIR"/README.md "$NEW_DIR"/asset-references.md; do
48
+ [ -f "$f" ] && sed "${SED_INPLACE[@]}" "s|$OLD|$NEW|g" "$f"
49
+ done
50
+
51
+ # config.yaml: only the identity field. A broad replace would corrupt env-var
52
+ # names, comments, and any value that legitimately contains $OLD.
53
+ CFG="$NEW_DIR/config.yaml"
54
+ if [ -f "$CFG" ]; then
55
+ sed "${SED_INPLACE[@]}" "s|^agent: $FN/$OLD$|agent: $FN/$NEW|" "$CFG"
56
+ fi
57
+
58
+ while IFS= read -r f; do
59
+ case "$f" in
60
+ *"_archive/"*) continue ;;
61
+ *"/logs/"*) continue ;;
62
+ *"/log/runs/"*) continue ;;
63
+ *"/log/feedback/"*) continue ;;
64
+ *"/playbook/"*) continue ;;
65
+ *) sed "${SED_INPLACE[@]}" "s|$FN/$OLD|$FN/$NEW|g" "$f" ;;
66
+ esac
67
+ done < <(grep -rl "$FN/$OLD" --include='*.md' --include='*.yaml' --include='*.json' --include='*.sh' --include='*.txt' "$ROOT" 2>/dev/null)
68
+
69
+ OLD_CMD="$ROOT/.claude/commands/$OLD.md"
70
+ NEW_CMD="$ROOT/.claude/commands/$NEW.md"
71
+ if [ -f "$OLD_CMD" ]; then
72
+ mv "$OLD_CMD" "$NEW_CMD"
73
+ sed "${SED_INPLACE[@]}" "s|$OLD|$NEW|g" "$NEW_CMD"
74
+ echo " Renamed slash command: .claude/commands/$OLD.md → $NEW.md"
75
+ fi
76
+
77
+ LOG_DIR="$ROOT/chief-of-staff/logs/$(date +%Y-%m)"
78
+ mkdir -p "$LOG_DIR"
79
+ LOG_FILE="$LOG_DIR/operations-$(date +%Y-%m-%d).md"
80
+ {
81
+ echo ""
82
+ echo "## $TIMESTAMP — rename-agent: $FN/$OLD → $FN/$NEW"
83
+ } >> "$LOG_FILE"
84
+
85
+ echo ""
86
+ echo "Files mentioning '$OLD' that were NOT auto-updated (review manually):"
87
+ grep -rln "$OLD" "$ROOT" 2>/dev/null | grep -v "_archive\|/logs/\|/log/runs/\|/log/feedback/\|/playbook/" | sed "s|$ROOT/| - |" || echo " (none found)"
88
+
89
+ echo ""
90
+ echo "✓ Rename complete."
91
+ echo " Operation log: $LOG_FILE"
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ # save-state.sh — write workspace state.md
3
+ #
4
+ # In v1, workspace = project. state.md lives at workspace root.
5
+ # Format: see conventions.md § "State file format". Normally Claude writes
6
+ # state.md directly when asked. This script exists for external invocation
7
+ # or scripted updates.
8
+ #
9
+ # Usage: bash scripts/save-state.sh "<state notes (multiline OK)>"
10
+
11
+ set -euo pipefail
12
+
13
+ if [ $# -lt 1 ]; then
14
+ echo "Usage: $0 \"<state notes>\""
15
+ exit 1
16
+ fi
17
+
18
+ NOTES="$*"
19
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
20
+ STATE_FILE="$ROOT/state.md"
21
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
22
+
23
+ cat > "$STATE_FILE" << EOF
24
+ ---
25
+ updated: $TIMESTAMP
26
+ ---
27
+
28
+ $NOTES
29
+ EOF
30
+
31
+ echo "✓ Saved workspace state"
32
+ echo " $STATE_FILE"