@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
@@ -9,7 +9,7 @@ Cross-domain pattern detection matters. A lesson observed in Twitter automation
9
9
  ## Files
10
10
 
11
11
  - `agent.md` — orchestrator contract
12
- - `subagents/` — pattern-detector, lesson-drafter, promotion-arbiter
12
+ - `subagents/` — pattern-detector, lesson-drafter
13
13
  - `playbook/` — the dreamer's own lessons (lessons about how to learn)
14
14
  - `logs/` — its own runs
15
15
  - `state.md` — last processed cutoff
@@ -17,7 +17,7 @@ Cross-domain pattern detection matters. A lesson observed in Twitter automation
17
17
 
18
18
  ## Invocation
19
19
 
20
- Nightly via the native desktop scheduler. Register with `roster schedule install` — each fire spawns a fresh CLI session in the workspace, loads `CONTEXT.md`, invokes the `roster-orchestrator` skill, and dispatches the dreamer in isolated subagent context. See `conventions.md` § Schedules and [ADR-0001](../../docs/adr/0001-scheduling-architecture.md) for the model. Subscription-billed only; `claude -p` and the Anthropic Agent SDK are banned and enforced by `roster doctor`.
20
+ Nightly via the native desktop scheduler. Register with `roster schedule install` — each fire spawns a fresh CLI session in the workspace, loads `CONTEXT.md`, invokes the `roster-orchestrator` skill, and dispatches the dreamer in isolated subagent context. See `conventions.md` § Schedules for the model.
21
21
 
22
22
  On-demand from a session: "Run the dreamer on the last week's outreach runs across all projects."
23
23
 
@@ -45,7 +45,6 @@ Typically scheduled nightly via cron or `/schedule`. When invoked without a plan
45
45
 
46
46
  - `pattern-detector.md` — finds patterns across runs+feedback
47
47
  - `lesson-drafter.md` — drafts a single lesson in schema format
48
- - `promotion-arbiter.md` — decides project vs global scope for validated lessons
49
48
 
50
49
  ## Tools and bindings
51
50
 
@@ -1,11 +1,9 @@
1
1
  plan: nightly-reflection
2
2
  description: |
3
- Reads runs and feedback across all agents and projects since the last
4
- cutoff, detects patterns, drafts lesson candidates, surfaces them for HITL
5
- approval via Slack #admin, and writes approved lessons to the relevant
6
- playbook directories. Promotes project-scoped lessons to global when the
7
- pattern is observed in 2+ projects. Updates dreamer/state.md with the new
8
- cutoff and a summary.
3
+ Reads runs and feedback across all agents since the last cutoff, detects
4
+ patterns, drafts lesson candidates, surfaces them for HITL approval via
5
+ Slack #admin, and writes approved lessons to each agent's playbook.
6
+ Updates dreamer/state.md with the new cutoff and a summary.
9
7
 
10
8
  inputs:
11
9
  mode:
@@ -14,7 +12,7 @@ inputs:
14
12
  description: nightly | weekly | on-demand. Selects how aggressively to scan and how to weight evidence.
15
13
  scope:
16
14
  required: false
17
- description: Limit to one project (slug) or one agent (function/agent) — useful for on-demand runs.
15
+ description: Limit to one agent (function/agent) — useful for on-demand runs.
18
16
  since:
19
17
  required: false
20
18
  description: ISO timestamp cutoff. If omitted, uses last_processed_through from dreamer/state.md.
@@ -24,7 +22,6 @@ outputs:
24
22
  candidates_drafted: integer
25
23
  candidates_approved: integer
26
24
  lessons_written: integer
27
- lessons_promoted: integer
28
25
  conflicts_surfaced: integer
29
26
 
30
27
  steps:
@@ -35,9 +32,9 @@ steps:
35
32
 
36
33
  - id: identify_material
37
34
  description: |
38
- Walk every agent's <function>/<agent>/projects/<project>/log/runs/<YYYY-MM>/
39
- and log/feedback/<YYYY-MM>/ for files newer than the cutoff. Match runs
40
- to feedback by filename. Apply ${inputs.scope} filter if provided.
35
+ Walk every agent's <function>/<agent>/log/runs/<YYYY-MM>/ and
36
+ log/feedback/<YYYY-MM>/ for files newer than the cutoff. Match runs to
37
+ feedback by filename. Apply ${inputs.scope} filter if provided.
41
38
 
42
39
  - id: detect_patterns
43
40
  subagent: pattern-detector
@@ -62,52 +59,41 @@ steps:
62
59
  description: |
63
60
  For each candidate that meets threshold or extends an existing lesson,
64
61
  draft a lesson in schema format with frontmatter (id, source: dreamer,
65
- scope: project|global, status: candidate, agent, created). Place drafts
66
- in dreamer/pending/.
62
+ status: candidate, agent, created). Place drafts in
63
+ <function>/<agent>/pending/.
67
64
  args:
68
65
  input_from: accumulate_evidence
69
66
 
70
- - id: arbitrate_promotion
71
- subagent: promotion-arbiter
72
- description: |
73
- For any project lesson validated in 2+ projects, decide whether to
74
- promote to global scope. Returns project vs global designation per
75
- candidate.
76
- args:
77
- input_from: draft_lessons
78
-
79
67
  - id: hitl_routing
80
68
  description: |
81
- Post all candidates and promotions to Slack #admin (channel from
69
+ Post all candidates to Slack #admin (channel from
82
70
  SLACK_HITL_CHANNEL_ADMIN env var) as threaded messages, one per
83
71
  candidate. Format: "Candidate lesson <id>: <title>. Approve / Reject /
84
72
  Defer." TTL 7 days. If Slack unavailable, queue candidates locally in
85
- dreamer/pending/ and retry next run.
73
+ <function>/<agent>/pending/ and retry next run.
86
74
  approval: slack
87
75
 
88
76
  - id: apply_approvals
89
77
  description: |
90
- On approval, write the lesson to the correct location:
91
- - Project-scoped: <function>/<agent>/projects/<project>/playbook/L-...md
92
- with scope: project
93
- - Promoted to global: <function>/<agent>/playbook/L-...md with
94
- scope: global AND mark project lesson promoted_to_global: true
95
- - Retired: update existing lesson's status: retired with reason
96
- All dreamer-written lessons get source: dreamer in frontmatter.
97
- Respect human-written lessons (source: human) — never modify or
98
- supersede without explicit HITL approval.
78
+ On approval, move the candidate file from <function>/<agent>/pending/
79
+ to <function>/<agent>/playbook/L-...md. There is no scope decision;
80
+ v1 has a single playbook per agent. All dreamer-written lessons get
81
+ source: dreamer in frontmatter. Respect human-written lessons
82
+ (source: human) never modify or supersede without explicit HITL
83
+ approval. Retired candidates update an existing lesson's status:
84
+ retired with reason.
99
85
 
100
86
  - id: update_state
101
87
  description: |
102
88
  Write timestamp + summary to dreamer/state.md:
103
89
  last_processed_through: <ISO timestamp>
104
- last_run_summary: drafted N, approved M, written K, promoted P
90
+ last_run_summary: drafted N, approved M, written K
105
91
 
106
92
  - id: write_run_log
107
93
  description: |
108
94
  Write run details to dreamer/logs/<YYYY-MM>/<YYYY-MM-DD-HHMM>.md
109
- including: material processed (counts by project and agent), patterns
110
- detected, lesson candidates drafted (Slack thread links), promotion
111
- candidates, approvals applied, conflicts surfaced.
95
+ including: material processed (counts by agent), patterns detected,
96
+ lesson candidates drafted (Slack thread links), approvals applied,
97
+ conflicts surfaced.
112
98
 
113
99
  approval_channel: slack
@@ -9,20 +9,17 @@ Take a candidate pattern and draft a lesson file in the schema defined in `conve
9
9
  - `pattern` (object): output from pattern-detector
10
10
  - `existing_lesson` (object, optional): if extending an existing lesson, the current version
11
11
  - `agent` (string): which agent
12
- - `project` (string): which project sourced it
13
12
 
14
13
  ## Output
15
14
 
16
15
  ```yaml
17
16
  suggested_filename: L-2026-04-26-001.md
18
- suggested_path: <function>/<agent>/projects/<project>/playbook/ # or <function>/<agent>/playbook/
17
+ suggested_path: <function>/<agent>/playbook/
19
18
  status: candidate
20
19
  lesson_markdown: |
21
20
  ---
22
21
  id: L-2026-04-26-001
23
22
  source: dreamer
24
- scope: project # or global
25
- project: _demo # or "—" if scope=global
26
23
  agent: sdr
27
24
  ...full frontmatter per conventions...
28
25
  ---
@@ -31,7 +28,6 @@ lesson_markdown: |
31
28
 
32
29
  ## Pattern observed
33
30
  ## Recommendation
34
- ## Why this might be project-specific
35
31
  ## Retirement criteria
36
32
  ```
37
33
 
@@ -43,9 +39,8 @@ None.
43
39
 
44
40
  - Use the exact schema in `conventions.md`. Don't invent fields.
45
41
  - Always set `source: dreamer`.
46
- - Default to `scope: project` unless explicitly handling a promotion case.
47
42
  - Cite evidence in body, not just frontmatter.
48
- - Body has 4 sections: pattern, recommendation, scope reasoning, retirement criteria. That's it.
43
+ - Body has 3 sections: pattern, recommendation, retirement criteria. That's it.
49
44
 
50
45
  ## Quality bar
51
46
 
@@ -1,3 +1,7 @@
1
+ > **Example content — replace with your project's actuals.**
2
+ > This file ships filled with an illustrative brand ("Acme Corp") so you can
3
+ > see the expected shape. Overwrite freely; no agent will warn if you do.
4
+
1
5
  # Asset Links — Acme Corp
2
6
 
3
7
  ## Brand
@@ -1,3 +1,7 @@
1
+ > **Example content — replace with your project's actuals.**
2
+ > This file ships filled with an illustrative brand ("Acme Corp") so you can
3
+ > see the expected shape. Overwrite freely; no agent will warn if you do.
4
+
1
5
  # Brand Book — Acme Corp
2
6
 
3
7
  ## Logo
@@ -1,3 +1,7 @@
1
+ > **Example content — replace with your project's actuals.**
2
+ > This file ships filled with an illustrative brand ("Acme Corp") so you can
3
+ > see the expected shape. Overwrite freely; no agent will warn if you do.
4
+
1
5
  # Messaging — Acme Corp
2
6
 
3
7
  ## Headline value props
@@ -1,3 +1,7 @@
1
+ > **Example content — replace with your project's actuals.**
2
+ > This file ships filled with an illustrative brand ("Acme Corp") so you can
3
+ > see the expected shape. Overwrite freely; no agent will warn if you do.
4
+
1
5
  # Voice — Acme Corp
2
6
 
3
7
  ## Adjectives describing the brand voice
@@ -42,7 +42,7 @@ PASSED=()
42
42
  if [ ! -f "$AGENT_DIR/agent.md" ]; then
43
43
  FAILURES+=("[$FN/$AGENT/agent.md] missing")
44
44
  else
45
- REQUIRED_SECTIONS=("## Purpose" "## Inputs" "## Plans" "## Subagents" "## Tools and bindings" "## Outputs" "## Approval" "## Lessons protocol")
45
+ REQUIRED_SECTIONS=("## Purpose" "## Inputs" "## Plans" "## Subagents" "## Outputs" "## Approval" "## Lessons protocol")
46
46
  MISSING=()
47
47
  for section in "${REQUIRED_SECTIONS[@]}"; do
48
48
  if ! grep -qF "$section" "$AGENT_DIR/agent.md"; then
@@ -56,6 +56,14 @@ else
56
56
  PASSED+=("[$FN/$AGENT/agent.md] all required sections present")
57
57
  fi
58
58
 
59
+ # ## Tools and bindings is required ONLY for agents that use external tools.
60
+ # Missing → warning, not failure (agents reading only workspace guidelines
61
+ # don't need it). The chief-of-staff create-agent guided flow adds the
62
+ # section when the user names tools.
63
+ if ! grep -qF "## Tools and bindings" "$AGENT_DIR/agent.md"; then
64
+ WARNINGS+=("[$FN/$AGENT/agent.md] '## Tools and bindings' not declared — fine for tool-less agents; required if this agent calls external APIs")
65
+ fi
66
+
59
67
  # Steps section should NOT be present anymore — workflows live in plans/
60
68
  if grep -qE '^## Steps' "$AGENT_DIR/agent.md"; then
61
69
  WARNINGS+=("[$FN/$AGENT/agent.md] still has a '## Steps' section — workflow logic should live in plans/<plan>.yaml, not agent.md")
@@ -105,6 +113,62 @@ else
105
113
  PASSED+=("[$FN/$AGENT/README.md] present")
106
114
  fi
107
115
 
116
+ # config.yaml — agent config (guideline refs + tool bindings).
117
+ # Schema check: single-document mapping with agent=$FN/$AGENT, plans_dir,
118
+ # guideline_refs (mapping), tools (mapping). Drift here breaks the runtime
119
+ # loader (Phase 2) and `chief-of-staff create-agent` reuse.
120
+ if [ ! -f "$AGENT_DIR/config.yaml" ]; then
121
+ FAILURES+=("[$FN/$AGENT/config.yaml] missing")
122
+ FAILURES+=(" → Suggested fix: add config.yaml at agent root with at least 'agent: $FN/$AGENT' and 'plans_dir: ./plans/'")
123
+ elif command -v python3 >/dev/null 2>&1; then
124
+ CFG_RC=0
125
+ CFG_MSG="$(AGENT_EXPECT="$FN/$AGENT" CFG_PATH="$AGENT_DIR/config.yaml" python3 - <<'PYEOF' 2>&1
126
+ import os, sys
127
+ try:
128
+ import yaml
129
+ except ImportError:
130
+ sys.stderr.write("pyyaml-missing")
131
+ sys.exit(2)
132
+ expect = os.environ["AGENT_EXPECT"]
133
+ path = os.environ["CFG_PATH"]
134
+ with open(path) as f:
135
+ try:
136
+ doc = yaml.safe_load(f)
137
+ except yaml.YAMLError as e:
138
+ sys.stderr.write(f"yaml-parse-error: {e}")
139
+ sys.exit(1)
140
+ if not isinstance(doc, dict):
141
+ sys.stderr.write("not-a-mapping")
142
+ sys.exit(1)
143
+ errs = []
144
+ agent = doc.get("agent")
145
+ if agent != expect:
146
+ errs.append(f"agent field is {agent!r}, expected {expect!r}")
147
+ if "plans_dir" not in doc:
148
+ errs.append("missing plans_dir")
149
+ gr = doc.get("guideline_refs")
150
+ if gr is not None and not isinstance(gr, dict):
151
+ errs.append("guideline_refs is not a mapping")
152
+ tools = doc.get("tools")
153
+ if tools is not None and not isinstance(tools, dict):
154
+ errs.append("tools is not a mapping")
155
+ if errs:
156
+ sys.stderr.write("; ".join(errs))
157
+ sys.exit(1)
158
+ PYEOF
159
+ )" || CFG_RC=$?
160
+ if [ $CFG_RC -eq 0 ]; then
161
+ PASSED+=("[$FN/$AGENT/config.yaml] valid (schema)")
162
+ elif [ $CFG_RC -eq 2 ]; then
163
+ PASSED+=("[$FN/$AGENT/config.yaml] present (schema not validated, pyyaml missing)")
164
+ else
165
+ FAILURES+=("[$FN/$AGENT/config.yaml] $CFG_MSG")
166
+ FAILURES+=(" → Suggested fix: open the file and ensure it is a single YAML mapping with 'agent: $FN/$AGENT', 'plans_dir', a 'guideline_refs:' mapping, and a 'tools:' mapping (may be empty)")
167
+ fi
168
+ else
169
+ PASSED+=("[$FN/$AGENT/config.yaml] present (schema not validated, python3 missing)")
170
+ fi
171
+
108
172
  # .mcp.json valid JSON
109
173
  if [ ! -f "$AGENT_DIR/.mcp.json" ]; then
110
174
  WARNINGS+=("[$FN/$AGENT/.mcp.json] missing (no agent-scoped MCPs configured)")
@@ -168,53 +232,18 @@ else
168
232
  PASSED+=("[$FN/$AGENT/playbook/] present")
169
233
  fi
170
234
 
171
- # projects/_template/ exists
172
- if [ ! -d "$AGENT_DIR/projects/_template" ]; then
173
- FAILURES+=("[$FN/$AGENT/projects/_template/] missing new instances cannot be created without it")
174
- FAILURES+=(" → Suggested fix: rebuild via 'bash scripts/new-agent.sh $FN $AGENT' (will fail if exists; manually copy from gtm/sdr/projects/_template/ as reference)")
175
- else
176
- PASSED+=("[$FN/$AGENT/projects/_template/] present")
177
- fi
178
-
179
- # === Each instance ===
180
- INSTANCES=()
181
- while IFS= read -r path; do
182
- INSTANCES+=("$path")
183
- done < <(find "$AGENT_DIR/projects" -maxdepth 1 -mindepth 1 -type d -not -name '_template' 2>/dev/null || true)
184
-
185
- for inst in "${INSTANCES[@]}"; do
186
- REL="${inst#$ROOT/}"
187
- PROJECT_NAME=$(basename "$inst")
188
-
189
- CONFIG="$inst/config/default.yaml"
190
- if [ ! -f "$CONFIG" ]; then
191
- FAILURES+=("[$REL/config/default.yaml] missing")
192
- else
193
- if command -v python3 >/dev/null 2>&1; then
194
- if ! python3 -c "import yaml; list(yaml.safe_load_all(open('$CONFIG')))" 2>/dev/null; then
195
- FAILURES+=("[$REL/config/default.yaml] YAML parse error")
196
- else
197
- DECLARED=$(python3 -c "import yaml; docs = list(yaml.safe_load_all(open('$CONFIG'))); print((docs[0] or {}).get('project', ''))" 2>/dev/null || echo "")
198
- if [ "$DECLARED" != "$PROJECT_NAME" ]; then
199
- FAILURES+=("[$REL/config/default.yaml] project field '$DECLARED' doesn't match folder '$PROJECT_NAME'")
200
- else
201
- PASSED+=("[$REL/config/default.yaml] valid")
202
- fi
203
- fi
204
- fi
205
- fi
206
-
207
- for d in log/runs log/feedback playbook; do
208
- if [ ! -d "$inst/$d" ]; then
209
- WARNINGS+=("[$REL/$d/] missing")
210
- fi
211
- done
212
-
213
- if [ ! -f "$inst/asset-references.md" ]; then
214
- WARNINGS+=("[$REL/asset-references.md] missing")
235
+ # Flat-shape directories
236
+ for d in logs/runs logs/feedback pending; do
237
+ if [ ! -d "$AGENT_DIR/$d" ]; then
238
+ WARNINGS+=("[$FN/$AGENT/$d/] missing")
215
239
  fi
216
240
  done
217
241
 
242
+ # asset-references.md at agent root
243
+ if [ ! -f "$AGENT_DIR/asset-references.md" ]; then
244
+ WARNINGS+=("[$FN/$AGENT/asset-references.md] missing")
245
+ fi
246
+
218
247
  # === Status ===
219
248
  if [ ${#FAILURES[@]} -gt 0 ]; then
220
249
  STATUS="fail"
@@ -265,7 +294,6 @@ N_PASS=${#PASSED[@]}
265
294
  echo "- $N_PASS passed"
266
295
  echo "- $N_WARN warnings"
267
296
  echo "- $N_FAIL failures"
268
- echo "- ${#INSTANCES[@]} instance(s) audited"
269
297
  echo ""
270
298
  if [ $N_FAIL -gt 0 ]; then
271
299
  echo "## Failures"
@@ -291,7 +319,6 @@ N_PASS=${#PASSED[@]}
291
319
 
292
320
  echo "Audit: $FN/$AGENT — $STATUS"
293
321
  echo " Passed: $N_PASS, Warnings: $N_WARN, Failures: $N_FAIL"
294
- echo " Instances audited: ${#INSTANCES[@]}"
295
322
  [ $N_FAIL -gt 0 ] && {
296
323
  echo "Failures:"
297
324
  for line in "${FAILURES[@]}"; do echo " $line"; done
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # audit-repo.sh — full repo audit; runs project + agent audits, plus repo-level checks
2
+ # audit-repo.sh — full workspace audit; runs agent audits and repo-level checks
3
3
  # Usage: bash scripts/audit-repo.sh
4
4
 
5
5
  set -euo pipefail
@@ -51,30 +51,34 @@ for f in CLAUDE.md conventions.md README.md; do
51
51
  fi
52
52
  done
53
53
 
54
- # Build a regex of registered functions for matching grandparent dirs.
55
- REGISTERED_FNS_PIPE=$(read_functions 2>/dev/null | tr '\n' '|' | sed 's/|$//')
54
+ # config/project.yaml workspace identity (v1 shape)
55
+ if [ ! -f "$ROOT/config/project.yaml" ]; then
56
+ REPO_FAILURES+=("[config/project.yaml] missing — workspace identity required")
57
+ elif command -v python3 >/dev/null 2>&1; then
58
+ if ! python3 -c "import yaml; yaml.safe_load(open('$ROOT/config/project.yaml'))" 2>/dev/null; then
59
+ REPO_FAILURES+=("[config/project.yaml] YAML parse error")
60
+ else
61
+ REPO_PASSED+=("[config/project.yaml] valid")
62
+ fi
63
+ fi
56
64
 
57
- # Find orphaned instances (instance folder exists but agent doesn't)
58
- ORPHANS=()
59
- while IFS= read -r path; do
60
- ORPHANS+=("$path")
61
- done < <(find "$ROOT" -type d -path "*/projects/*" -not -path "*/projects/_template*" -not -path "*/_archive/*" 2>/dev/null | while read p; do
62
- PARENT=$(dirname $(dirname "$p"))
63
- if [ -d "$PARENT" ] && [ ! -f "$PARENT/agent.md" ]; then
64
- # This is a project folder under a non-agent that's actually projects/ root
65
- # We only care about instances: <fn>/<agent>/projects/<proj>/ where agent.md is missing
66
- GRANDPARENT=$(dirname "$PARENT")
67
- GP_NAME=$(basename "$GRANDPARENT")
68
- if [ -n "$REGISTERED_FNS_PIPE" ] && echo "$GP_NAME" | grep -qE "^($REGISTERED_FNS_PIPE)\$"; then
69
- echo "$p"
65
+ # guidelines/ cross-agent substrate
66
+ if [ ! -d "$ROOT/guidelines" ]; then
67
+ REPO_FAILURES+=("[guidelines/] missing workspace substrate dir required")
68
+ else
69
+ REPO_PASSED+=("[guidelines/] present")
70
+ for f in voice.md messaging.md brand-book.md asset-links.md; do
71
+ if [ ! -f "$ROOT/guidelines/$f" ]; then
72
+ REPO_WARNINGS+=("[guidelines/$f] missingrequired substrate file")
70
73
  fi
74
+ done
75
+ if [ ! -d "$ROOT/guidelines/icps" ] || [ -z "$(find "$ROOT/guidelines/icps" -maxdepth 1 -name '*.md' -type f 2>/dev/null | head -1)" ]; then
76
+ REPO_WARNINGS+=("[guidelines/icps/] empty or missing — at least one persona file required")
71
77
  fi
72
- done)
78
+ fi
73
79
 
74
- for orphan in "${ORPHANS[@]:-}"; do
75
- REL="${orphan#$ROOT/}"
76
- REPO_WARNINGS+=("[$REL] orphaned instance — parent agent has no agent.md")
77
- done
80
+ # Build a regex of registered functions for matching grandparent dirs.
81
+ REGISTERED_FNS_PIPE=$(read_functions 2>/dev/null | tr '\n' '|' | sed 's/|$//')
78
82
 
79
83
  # Registered function should have a folder
80
84
  while IFS= read -r fn; do
@@ -109,7 +113,7 @@ if [ -f "$ENV_EXAMPLE" ]; then
109
113
  fi
110
114
 
111
115
  # Function-shaped top-level dirs not in the registry
112
- KNOWN_NON_FUNCTIONS="dreamer chief-of-staff projects scripts logs _archive"
116
+ KNOWN_NON_FUNCTIONS="dreamer chief-of-staff scripts logs _archive"
113
117
  for dir in "$ROOT"/*/; do
114
118
  basename=$(basename "$dir")
115
119
  [[ "$basename" == .* ]] && continue
@@ -123,25 +127,6 @@ for dir in "$ROOT"/*/; do
123
127
  fi
124
128
  done
125
129
 
126
- # === Run audit-project for each project ===
127
- PROJECTS=()
128
- while IFS= read -r path; do
129
- PROJECTS+=("$path")
130
- done < <(find "$ROOT/projects" -maxdepth 1 -mindepth 1 -type d -not -name '_template' 2>/dev/null || true)
131
-
132
- PROJECT_RESULTS=()
133
- for proj_path in "${PROJECTS[@]:-}"; do
134
- PROJ=$(basename "$proj_path")
135
- RESULT=$(bash "$ROOT/scripts/audit-project.sh" "$PROJ" 2>&1 | head -5 || echo " (audit failed)")
136
- PROJECT_RESULTS+=("### $PROJ")
137
- PROJECT_RESULTS+=("\`\`\`")
138
- while IFS= read -r line; do
139
- PROJECT_RESULTS+=("$line")
140
- done <<< "$RESULT"
141
- PROJECT_RESULTS+=("\`\`\`")
142
- PROJECT_RESULTS+=("")
143
- done
144
-
145
130
  # === Run audit-agent for each agent ===
146
131
  AGENTS=()
147
132
  while IFS= read -r fn; do
@@ -187,7 +172,6 @@ fi
187
172
  echo "# Repo Audit"
188
173
  echo ""
189
174
  echo "## Summary"
190
- echo "- Projects audited: ${#PROJECTS[@]}"
191
175
  echo "- Agents audited: ${#AGENTS[@]}"
192
176
  echo "- Repo-level passed: ${#REPO_PASSED[@]}"
193
177
  echo "- Repo-level warnings: ${#REPO_WARNINGS[@]}"
@@ -214,12 +198,6 @@ fi
214
198
  done
215
199
  echo ""
216
200
  fi
217
- echo "## Project audits (summaries)"
218
- echo ""
219
- for line in "${PROJECT_RESULTS[@]:-}"; do
220
- echo "$line"
221
- done
222
- echo ""
223
201
  echo "## Agent audits (summaries)"
224
202
  echo ""
225
203
  for line in "${AGENT_RESULTS[@]:-}"; do
@@ -231,7 +209,7 @@ fi
231
209
 
232
210
  # Print summary
233
211
  echo "Repo audit: $STATUS"
234
- echo " Projects: ${#PROJECTS[@]} | Agents: ${#AGENTS[@]}"
212
+ echo " Agents: ${#AGENTS[@]}"
235
213
  echo " Repo-level: ${#REPO_PASSED[@]} passed, ${#REPO_WARNINGS[@]} warnings, ${#REPO_FAILURES[@]} failures"
236
214
  [ ${#REPO_FAILURES[@]} -gt 0 ] && {
237
215
  echo "Repo failures:"
@@ -215,7 +215,7 @@ if [ "$WITH_EXPERT" = "true" ]; then
215
215
  This is a stub. Fill in the expert system prompt for this function.
216
216
 
217
217
  Experts shape SUBSTRATE (project guidelines), not artifacts. They critique
218
- and generate guideline files in \`projects/<project>/guidelines/\`.
218
+ and generate guideline files in \`guidelines/\` at the workspace root.
219
219
 
220
220
  Required sections (see other EXPERT.md files for examples once they exist):
221
221
  - Identity (1 paragraph)
@@ -10,7 +10,7 @@ Conventions:
10
10
  ## Current inhabitants
11
11
 
12
12
  - `functions.sh` — read/validate the function registry at `.config/functions.yaml`. Pure bash + falls back to `python3` + `pyyaml` when available for safer YAML parsing.
13
- - `bindings-prompt.sh` — interactive prompts for per-tool bindings during `new-agent-instance.sh`. Requires `python3` + `pyyaml` for the YAML output rendering (falls back gracefully when unavailable).
13
+ - `bindings-prompt.sh` — **disabled in v1.0**. Phase 2 will rebuild this around the env-merge loader (config.yaml `tools:` metadata + `/.env` values). Until then, invocation aborts with manual-configuration instructions (edit agent.md `## Tools and bindings` mirror the YAML block into `<agent>/config.yaml` add env-var values to `/.env`). The file remains in the tarball + executable so smoke continues to assert presence; the runtime behavior is the guard message.
14
14
 
15
15
  Example future additions:
16
16
  - `lib/lesson.sh` — read/write lesson files, validate schema