@firatcand/roster 0.1.0

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/agents/critic.md +74 -0
  4. package/agents/enricher.md +56 -0
  5. package/agents/lesson-drafter.md +64 -0
  6. package/agents/pattern-detector.md +62 -0
  7. package/agents/promotion-arbiter.md +71 -0
  8. package/agents/prospector.md +51 -0
  9. package/agents/writer.md +58 -0
  10. package/bin/roster.js +2093 -0
  11. package/lib/.gitkeep +0 -0
  12. package/package.json +68 -0
  13. package/skills/chief-of-staff/SKILL.md +218 -0
  14. package/skills/dreamer/SKILL.md +112 -0
  15. package/skills/roster-orchestrator/SKILL.md +122 -0
  16. package/skills/sdr/SKILL.md +147 -0
  17. package/templates/CLAUDE.project.template.md +45 -0
  18. package/templates/CONTEXT.template.md +51 -0
  19. package/templates/env.example +25 -0
  20. package/templates/gitignore-defaults.txt +28 -0
  21. package/templates/scaffold/.config/functions.yaml +22 -0
  22. package/templates/scaffold/chief-of-staff/README.md +86 -0
  23. package/templates/scaffold/chief-of-staff/agent.md +122 -0
  24. package/templates/scaffold/chief-of-staff/logs/.gitkeep +0 -0
  25. package/templates/scaffold/chief-of-staff/plans/add-agent-to-project.yaml +45 -0
  26. package/templates/scaffold/chief-of-staff/plans/archive-project.yaml +51 -0
  27. package/templates/scaffold/chief-of-staff/plans/audit-agent.yaml +32 -0
  28. package/templates/scaffold/chief-of-staff/plans/audit-project.yaml +34 -0
  29. package/templates/scaffold/chief-of-staff/plans/audit-repo.yaml +26 -0
  30. package/templates/scaffold/chief-of-staff/plans/create-agent.yaml +123 -0
  31. package/templates/scaffold/chief-of-staff/plans/create-function.yaml +48 -0
  32. package/templates/scaffold/chief-of-staff/plans/create-project.yaml +65 -0
  33. package/templates/scaffold/chief-of-staff/plans/remove-agent-from-project.yaml +50 -0
  34. package/templates/scaffold/chief-of-staff/plans/rename-project.yaml +62 -0
  35. package/templates/scaffold/chief-of-staff/plans/unarchive-project.yaml +41 -0
  36. package/templates/scaffold/chief-of-staff/playbook/.gitkeep +0 -0
  37. package/templates/scaffold/conventions.md +608 -0
  38. package/templates/scaffold/design/.gitkeep +0 -0
  39. package/templates/scaffold/design/EXPERT.md +68 -0
  40. package/templates/scaffold/dreamer/README.md +32 -0
  41. package/templates/scaffold/dreamer/agent.md +101 -0
  42. package/templates/scaffold/dreamer/logs/.gitkeep +0 -0
  43. package/templates/scaffold/dreamer/pending/.gitkeep +0 -0
  44. package/templates/scaffold/dreamer/plans/nightly-reflection.yaml +113 -0
  45. package/templates/scaffold/dreamer/playbook/.gitkeep +0 -0
  46. package/templates/scaffold/dreamer/state.md +13 -0
  47. package/templates/scaffold/dreamer/subagents/lesson-drafter.md +56 -0
  48. package/templates/scaffold/dreamer/subagents/pattern-detector.md +55 -0
  49. package/templates/scaffold/dreamer/subagents/promotion-arbiter.md +64 -0
  50. package/templates/scaffold/gtm/EXPERT.md +83 -0
  51. package/templates/scaffold/gtm/sdr/.claude/settings.json +3 -0
  52. package/templates/scaffold/gtm/sdr/.mcp.json +21 -0
  53. package/templates/scaffold/gtm/sdr/README.md +46 -0
  54. package/templates/scaffold/gtm/sdr/agent.md +136 -0
  55. package/templates/scaffold/gtm/sdr/plans/cold-outreach.yaml +92 -0
  56. package/templates/scaffold/gtm/sdr/playbook/.gitkeep +0 -0
  57. package/templates/scaffold/gtm/sdr/projects/_demo/asset-references.md +7 -0
  58. package/templates/scaffold/gtm/sdr/projects/_demo/config/default.yaml +69 -0
  59. package/templates/scaffold/gtm/sdr/projects/_demo/log/feedback/.gitkeep +0 -0
  60. package/templates/scaffold/gtm/sdr/projects/_demo/log/runs/.gitkeep +0 -0
  61. package/templates/scaffold/gtm/sdr/projects/_demo/playbook/.gitkeep +0 -0
  62. package/templates/scaffold/gtm/sdr/subagents/critic.md +67 -0
  63. package/templates/scaffold/gtm/sdr/subagents/enricher.md +49 -0
  64. package/templates/scaffold/gtm/sdr/subagents/prospector.md +44 -0
  65. package/templates/scaffold/gtm/sdr/subagents/writer.md +51 -0
  66. package/templates/scaffold/logs/cron/.gitkeep +0 -0
  67. package/templates/scaffold/ops/.gitkeep +0 -0
  68. package/templates/scaffold/ops/EXPERT.md +84 -0
  69. package/templates/scaffold/product/.gitkeep +0 -0
  70. package/templates/scaffold/product/EXPERT.md +87 -0
  71. package/templates/scaffold/projects/_demo/CLAUDE.md +35 -0
  72. package/templates/scaffold/projects/_demo/README.md +16 -0
  73. package/templates/scaffold/projects/_demo/assets/.gitkeep +0 -0
  74. package/templates/scaffold/projects/_demo/config/default.yaml +28 -0
  75. package/templates/scaffold/projects/_demo/guidelines/asset-links.md +15 -0
  76. package/templates/scaffold/projects/_demo/guidelines/brand-book.md +25 -0
  77. package/templates/scaffold/projects/_demo/guidelines/icps/_persona-template.md +44 -0
  78. package/templates/scaffold/projects/_demo/guidelines/messaging.md +20 -0
  79. package/templates/scaffold/projects/_demo/guidelines/voice.md +29 -0
  80. package/templates/scaffold/projects/_demo/state.md +11 -0
  81. package/templates/scaffold/scripts/lib/README.md +13 -0
  82. package/templates/scaffold/scripts/lib/functions.sh +89 -0
  83. package/templates/scaffold/scripts/new-project.sh +125 -0
@@ -0,0 +1,87 @@
1
+ <!--
2
+ This expert prompt is opinionated. It reflects one founder's judgment about
3
+ which thinkers, frameworks, and skills are useful for this function. Replace
4
+ freely with your own perspectives — the practitioner panel, skills routing,
5
+ and stage filter are all customizable to your context.
6
+ -->
7
+
8
+ # Product Expert
9
+
10
+ Senior product leader advising a solo founder building products (default: B2B SaaS — adapt frameworks when context signals otherwise and state the adaptation). Challenge assumptions, identify gaps, produce specification-grade artifacts.
11
+
12
+ ## Scope
13
+
14
+ - **Critique**: Audit guideline files in `projects/<project>/guidelines/` related to product strategy — `messaging.md`, `competitors.md`, `do-and-dont.md`, `icps/*.md` (when product-led). Score, name gaps, recommend.
15
+ - **Generate guidelines**: Produce or refine these guideline files. Refine project `CLAUDE.md` identity when underspecified.
16
+ - **Guide**: Specification, positioning, analytics, research, tradeoff discussions. Strategic output — files only when the task asks for substrate.
17
+
18
+ You do **NOT** produce sprint-level backlog artifacts (individual tickets, per-sprint user stories, ad-hoc analytics dashboards, throwaway one-shot specs). PRDs, foundational requirements, and acceptance criteria are substrate when they shape a category-level decision — those you do produce via Specify mode. **Experts shape substrate; agents produce artifacts.**
19
+
20
+ ## Read-first protocol
21
+
22
+ On invocation, read:
23
+
24
+ 1. `projects/<project>/CLAUDE.md` — project identity
25
+ 2. `projects/<project>/guidelines/voice.md` and `icps/*` — audience and tone
26
+ 3. Existing guideline files relevant to the task
27
+ 4. `projects/<project>/state.md` — current focus
28
+
29
+ Ask only about gaps. Never re-ask what's in substrate. If multiple modes are plausible, state which mode you're entering before proceeding.
30
+
31
+ ## Operating modes
32
+
33
+ State the mode. Don't mix.
34
+
35
+ | Mode | Trigger | Behavior |
36
+ |---|---|---|
37
+ | **Specify** | Spec, requirements, user stories, acceptance criteria | product-spec (+ software-architect / ux-design if relevant) → intake → artifact |
38
+ | **Position** | Positioning, value props, messaging hierarchy | product-position (+ plg-skill if PLG-relevant) → intake → artifact |
39
+ | **Analyze** | Metrics, funnels, measurement framework | plg-skill if PLG-relevant → intake → recommendations |
40
+ | **Research** | Competitive analysis, market mapping | intake → artifact |
41
+ | **Advise** | Open question, tradeoff, decision framework | direct response, skills as needed |
42
+
43
+ When ambiguous, state your interpretation before producing output.
44
+
45
+ ## Mandatory intake (Specify / Position / Analyze / Research)
46
+
47
+ Ask only what's missing.
48
+
49
+ - **Specify**: problem and audience · desired user outcome (not feature description) · constraints (timeline, stack, dependencies) · definition of done · edge cases, risks, non-goals
50
+ - **Position**: product/feature being positioned · primary buyer and user · alternatives (competitors, workarounds, status quo) · defensible differentiation · product stage
51
+ - **Analyze**: question to answer · product stage · existing instrumentation · decisions this informs
52
+ - **Research**: category/segment · specific questions · known competitors · decision this feeds
53
+
54
+ In Advise mode, skip formal intake. Ask inline only if genuinely underspecified.
55
+
56
+ ## Skills
57
+
58
+ | Task | Skill |
59
+ |---|---|
60
+ | PRDs, feature specs, user stories, acceptance criteria, spec audits | product-spec |
61
+ | Positioning, messaging hierarchy, value props, category, differentiation | product-position |
62
+ | Architecture decisions, stack selection, monolith vs microservices, db choices, migration | software-architect |
63
+ | UX audits, flows, interaction critique, Gestalt/affordance review | ux-design |
64
+ | PLG strategy, freemium, activation metrics, PQLs, viral loops | plg-skill |
65
+
66
+ Prefer skill methodology over general reasoning when the task falls within their domain.
67
+
68
+ ## Output rules
69
+
70
+ - Generated guidelines write to `projects/<project>/guidelines/<file>.md`. Name the path before writing.
71
+ - Use must / should / may — never could / might. Every requirement testable.
72
+ - Open every artifact with a one-line summary of what it is and what decision it supports.
73
+ - Close every artifact with **Open Questions** — unresolved items, missing inputs, next steps.
74
+ - Tables for comparisons. Prose for reasoning.
75
+
76
+ ## Behavior rules
77
+
78
+ - **Challenge before you build.** Name weak assumptions, dependencies, gaps before producing.
79
+ - **Separate problem from solution.** Confirm the problem before specifying a feature.
80
+ - **Name tradeoffs.** State what every recommendation costs.
81
+ - **Scope ruthlessly.** Flag when scope exceeds a single shippable increment; suggest decomposition.
82
+ - **Be direct.** No "it depends" without conditions. No filler praise.
83
+ - **Stay in your lane.** Specification, positioning, analytics, research. Lightweight on execution; recommend domain handoff.
84
+
85
+ ## Stage filter
86
+
87
+ Early-stage: limited budget, no brand awareness, unvalidated assumptions. Bias toward learning over scaling. Flag every claim that depends on an unvalidated market, customer, or product assumption.
@@ -0,0 +1,35 @@
1
+ ---
2
+ project: _demo
3
+ type: example
4
+ created: 2026-05-03
5
+ ---
6
+
7
+ # Acme Corp — Demo Project
8
+
9
+ This is a sample project demonstrating how `roster` organizes work. Acme Corp is a fictional B2B SaaS company that helps small businesses automate their accounting workflows.
10
+
11
+ This demo is **safe to delete**. It exists to show the structure of a populated project. Real projects go in `projects/<your-project-name>/`.
12
+
13
+ ## Identity
14
+
15
+ - Product: Acme Books — accounting automation for SMBs
16
+ - Stage: early-stage SaaS, post-launch
17
+ - Audience: SMB owners and bookkeepers
18
+ - Primary motion: outbound to bookkeeping firms and SMB owners
19
+
20
+ ## Active agent instances
21
+
22
+ - `gtm/sdr/projects/_demo/` — outbound prospecting and cold outreach
23
+
24
+ ## Files in this project
25
+
26
+ - `CLAUDE.md` — this file
27
+ - `state.md` — session continuity (auto-updated)
28
+ - `guidelines/` — substrate (voice, ICPs, messaging, brand-book, etc.)
29
+
30
+ ## How to use as a learning example
31
+
32
+ 1. Browse `projects/_demo/guidelines/` to see what filled-in substrate looks like
33
+ 2. Browse `gtm/sdr/projects/_demo/config/default.yaml` to see how an agent instance is configured
34
+ 3. Try running the agent against this demo: `/sdr run cold-outreach for _demo` (will prompt for filled bindings — feel free to use placeholder values for the test)
35
+ 4. Delete this entire `_demo/` directory and its instance(s) when you're ready to start fresh
@@ -0,0 +1,16 @@
1
+ # _demo
2
+
3
+ Placeholder project for testing roster workflows. Rename or duplicate this directory to
4
+ create a real project — `scripts/new-project.sh <name>` automates that in Phase 2.
5
+
6
+ ## Structure
7
+
8
+ ```
9
+ projects/_demo/
10
+ ├── guidelines/ # written by function-level experts (added in Phase 2)
11
+ ├── config/default.yaml # per-project agent config (added in Phase 2)
12
+ └── state.md # session continuity notes (max 5 lines; updated via /save-state)
13
+ ```
14
+
15
+ In Phase 1 this directory only proves `roster init` writes files to the right place. The
16
+ full project substrate lands when Phase 2 ships `templates/scaffold/` (see ROS-17).
@@ -0,0 +1,28 @@
1
+ ---
2
+ project: _demo
3
+ created: 2026-05-03
4
+ ---
5
+
6
+ # Project-level config — Acme Corp demo
7
+ #
8
+ # Cross-agent defaults for this project. Agent-scoped config (per-instance
9
+ # tool bindings, channel caps, scoring thresholds) lives at:
10
+ # <function>/<agent>/projects/<project>/config/default.yaml
11
+ #
12
+ # Keep this file thin. It's read by chief-of-staff for audit reports and
13
+ # by any agent that needs project-wide signals.
14
+
15
+ # Display name shown in reports and Slack messages.
16
+ display_name: Acme Corp
17
+
18
+ # Stage: idea | pre-launch | early | growth | mature
19
+ stage: early
20
+
21
+ # Primary go-to-market motion. Drives default agent suggestions.
22
+ # Options: outbound | inbound | plg | hybrid
23
+ motion: outbound
24
+
25
+ # Default approval channel for HITL — used when an agent's instance config
26
+ # leaves approval_channel unset.
27
+ # Options: slack | inline | auto
28
+ approval_channel: auto
@@ -0,0 +1,15 @@
1
+ # Asset Links — Acme Corp
2
+
3
+ ## Brand
4
+ - Logo files: <Drive folder URL>
5
+ - Brand guidelines PDF: <Drive folder URL>
6
+
7
+ ## Templates
8
+ - Email template (cold outreach): <Drive doc URL>
9
+ - LinkedIn DM template: <Drive doc URL>
10
+ - Demo script: <Drive doc URL>
11
+
12
+ ## External
13
+ - Website: https://acmecorp.example.com
14
+ - Calendar booking: https://cal.com/acmecorp/intro
15
+ - Knowledge base: https://docs.acmecorp.example.com
@@ -0,0 +1,25 @@
1
+ # Brand Book — Acme Corp
2
+
3
+ ## Logo
4
+ - Wordmark "Acme" in deep navy
5
+ - Optional small icon (ledger lines)
6
+
7
+ ## Colors
8
+ - Primary: Navy (#1a2742)
9
+ - Secondary: Warm white (#fafaf6)
10
+ - Accent: Muted gold (#c9a85d)
11
+ - Error: Brick red (#a93f3f)
12
+
13
+ ## Typography
14
+ - Display: Söhne (or Inter as web fallback)
15
+ - Body: Inter
16
+ - Code: JetBrains Mono
17
+
18
+ ## Imagery
19
+ - Photography: real small businesses, daylight, no stock-art smiles
20
+ - Illustrations: line-art only, navy + gold, no soft gradients
21
+
22
+ ## Don't
23
+ - Don't pair navy + green — looks generic SaaS
24
+ - Don't use stock images of "diverse team in conference room"
25
+ - Don't use dramatic AI-generated illustrations
@@ -0,0 +1,44 @@
1
+ # <Persona Name>
2
+
3
+ Short slug for filename: `<slug>.md` (e.g., `founding-team-hiring-manager.md`).
4
+
5
+ ## Who they are
6
+ - Industry: <list>
7
+ - Company stage: <list>
8
+ - Company size: <range>
9
+ - Geography: <list or global>
10
+
11
+ ## Their role
12
+ - Title patterns: <list>
13
+ - Reports to: <list>
14
+ - Tenure: <typical>
15
+ - Day-to-day: <what they actually do>
16
+
17
+ ## What they care about
18
+ - Top 3 pains: <list>
19
+ - Top 3 goals: <list>
20
+ - What success looks like for them: <description>
21
+
22
+ ## Buying signals / triggers
23
+ Recent events or states that suggest they're a good fit RIGHT NOW:
24
+ - <signal — e.g., "company raised Series B in last 90 days">
25
+ - <signal — e.g., "hiring founding GTM role">
26
+ - <signal>
27
+
28
+ ## Engagement signals
29
+ Things they do publicly that suggest they're approachable:
30
+ - <signal — e.g., "posts on LinkedIn weekly">
31
+ - <signal — e.g., "responded to a founder DM publicly in last 30 days">
32
+
33
+ ## Disqualifiers
34
+ What makes someone NOT a fit even if they otherwise match:
35
+ - <e.g., "company in stealth — no public signals to personalize on">
36
+ - <e.g., "C-suite at >500 person company — wrong access pattern">
37
+
38
+ ## Channels they respond to
39
+ - Best: <list>
40
+ - Acceptable: <list>
41
+ - Avoid: <list>
42
+
43
+ ## Notes
44
+ <anything else that helps an agent know this persona>
@@ -0,0 +1,20 @@
1
+ # Messaging — Acme Corp
2
+
3
+ ## Headline value props
4
+ 1. **Reconciles your books in 80% less time** — primary proof point
5
+ 2. **Catches errors humans miss** — secondary, builds confidence
6
+ 3. **Works inside QuickBooks / Xero / Wave** — table stakes, but worth saying
7
+
8
+ ## Anti-positioning
9
+ - We are NOT trying to replace bookkeepers — we make them more productive
10
+ - We are NOT a generic AI tool — we're built specifically for small business accounting
11
+
12
+ ## Frame for cold outreach
13
+ - Open with a question about their accounting workflow
14
+ - Acknowledge that automation is a hot topic but most tools are generic
15
+ - Offer something specific: a workflow demo or a 15-min audit
16
+
17
+ ## Frame for inbound
18
+ - Lead with the time savings (concrete: "3 hours/week back")
19
+ - Show the integration logos (lower the perceived risk)
20
+ - Quote a real-feeling customer story
@@ -0,0 +1,29 @@
1
+ # Voice — Acme Corp
2
+
3
+ ## Adjectives describing the brand voice
4
+ 1. Practical
5
+ 2. Direct
6
+ 3. Reassuring
7
+
8
+ ## Tone
9
+ - We talk like a knowledgeable colleague, not a vendor.
10
+ - We acknowledge accounting is tedious — we don't pretend it's exciting.
11
+ - We respect the reader's time. Short sentences. No fluff.
12
+
13
+ ## Sentence length
14
+ Most sentences under 18 words. Very rarely longer.
15
+
16
+ ## Vocabulary
17
+ - Use plain words: "books" not "ledger entries", "match" not "reconcile"
18
+ - Avoid: "transformative", "revolutionary", "leveraging", "synergize"
19
+ - Industry terms allowed when they're unavoidable: GAAP, AR, AP, COGS
20
+
21
+ ## Channel-specific notes
22
+ - Email: warm + direct. Always one CTA per message.
23
+ - LinkedIn: a little more casual, less salesy.
24
+ - Website: most polished, but still conversational.
25
+
26
+ ## Anti-examples
27
+ - "We're transforming the way SMBs handle their books" — too generic, sounds like every SaaS pitch
28
+ - "Leverage our cutting-edge platform" — corporate speak
29
+ - "Hope this finds you well" — empty opener
@@ -0,0 +1,11 @@
1
+ ---
2
+ last_session: 2026-05-03
3
+ focus: (none — demo project)
4
+ ---
5
+
6
+ # Acme Corp — Session State
7
+
8
+ This file tracks short-term context across Claude Code sessions for this project. Updated via `/save-state` or by the user explicitly. Five lines max.
9
+
10
+ - Status: demo / illustrative
11
+ - Next task: replace with your real project, or delete `_demo/` entirely
@@ -0,0 +1,13 @@
1
+ # Shared script libraries
2
+
3
+ Helper functions for use across scripts. Empty for now — add as scripts grow.
4
+
5
+ Conventions:
6
+ - Bash: `<n>.sh`, sourced via `source "$(dirname $0)/lib/<n>.sh"`
7
+ - Python: `<n>.py` if needed (use `pip install --break-system-packages`)
8
+ - Keep functions narrow
9
+
10
+ Example future additions:
11
+ - `lib/lesson.sh` — read/write lesson files, validate schema
12
+ - `lib/run.sh` — append to run files, format frontmatter
13
+ - `lib/slack.sh` — HITL posting with retry
@@ -0,0 +1,89 @@
1
+ # scripts/lib/functions.sh — shared helpers for reading the functions registry.
2
+ # Source from a script that has $ROOT set to repo root:
3
+ # ROOT="$(cd "$(dirname "$0")/.." && pwd)"
4
+ # source "$ROOT/scripts/lib/functions.sh"
5
+ #
6
+ # Provides:
7
+ # read_functions — print one slug per line from .config/functions.yaml
8
+ # read_functions_with_metadata — print "<slug>\t<has_expert>" per line
9
+ # is_valid_function <slug> — return 0 if slug is registered, else 1
10
+
11
+ _have_pyyaml() {
12
+ command -v python3 >/dev/null 2>&1 && python3 -c "import yaml" >/dev/null 2>&1
13
+ }
14
+
15
+ read_functions() {
16
+ local config="${ROOT}/.config/functions.yaml"
17
+ if [ ! -f "$config" ]; then
18
+ echo "ERROR: $config not found" >&2
19
+ return 1
20
+ fi
21
+ if _have_pyyaml; then
22
+ python3 -c "
23
+ import yaml, sys
24
+ try:
25
+ with open('$config') as f:
26
+ data = yaml.safe_load(f) or {}
27
+ except yaml.YAMLError as e:
28
+ sys.stderr.write('ERROR: malformed YAML in $config: ' + str(e) + '\n')
29
+ sys.exit(1)
30
+ for fn in data.get('functions', []):
31
+ slug = fn.get('slug', '')
32
+ if slug:
33
+ print(slug)
34
+ " || return 1
35
+ else
36
+ grep -E '^[[:space:]]*-[[:space:]]*slug:[[:space:]]*' "$config" \
37
+ | sed -E 's/^[[:space:]]*-[[:space:]]*slug:[[:space:]]*//; s/[[:space:]]*$//'
38
+ fi
39
+ }
40
+
41
+ read_functions_with_metadata() {
42
+ local config="${ROOT}/.config/functions.yaml"
43
+ if [ ! -f "$config" ]; then
44
+ echo "ERROR: $config not found" >&2
45
+ return 1
46
+ fi
47
+ if _have_pyyaml; then
48
+ python3 -c "
49
+ import yaml, sys
50
+ try:
51
+ with open('$config') as f:
52
+ data = yaml.safe_load(f) or {}
53
+ except yaml.YAMLError as e:
54
+ sys.stderr.write('ERROR: malformed YAML in $config: ' + str(e) + '\n')
55
+ sys.exit(1)
56
+ for fn in data.get('functions', []):
57
+ slug = fn.get('slug', '')
58
+ has_expert = bool(fn.get('has_expert', False))
59
+ if slug:
60
+ print(slug + '\t' + ('true' if has_expert else 'false'))
61
+ " || return 1
62
+ else
63
+ # Fallback: awk over flat YAML; track current slug and emit when has_expert seen.
64
+ awk '
65
+ /^[[:space:]]*-[[:space:]]*slug:[[:space:]]*/ {
66
+ if (slug != "") print slug "\t" (he == "true" ? "true" : "false")
67
+ slug = $0
68
+ sub(/^[[:space:]]*-[[:space:]]*slug:[[:space:]]*/, "", slug)
69
+ sub(/[[:space:]]*$/, "", slug)
70
+ he = "false"
71
+ next
72
+ }
73
+ /^[[:space:]]*has_expert:[[:space:]]*/ {
74
+ v = $0
75
+ sub(/^[[:space:]]*has_expert:[[:space:]]*/, "", v)
76
+ sub(/[[:space:]]*$/, "", v)
77
+ he = v
78
+ }
79
+ END {
80
+ if (slug != "") print slug "\t" (he == "true" ? "true" : "false")
81
+ }
82
+ ' "$config"
83
+ fi
84
+ }
85
+
86
+ is_valid_function() {
87
+ local fn="$1"
88
+ read_functions 2>/dev/null | grep -Fxq "$fn"
89
+ }
@@ -0,0 +1,125 @@
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