open-xmen 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 (60) hide show
  1. package/.cerebro/.gitignore +27 -0
  2. package/.cerebro/cerebro-identity.md +76 -0
  3. package/.cerebro/docs/agent-mapping.md +54 -0
  4. package/.cerebro/docs/cerebro-workflow.md +115 -0
  5. package/.cerebro/docs/orchestration.md +28 -0
  6. package/.cerebro/docs/overview.md +44 -0
  7. package/.cerebro/docs/skill-policy.md +25 -0
  8. package/.cerebro/integrations/semble.md +30 -0
  9. package/.cerebro/opencode/model-routing.md +37 -0
  10. package/.cerebro/schemas/boulder.schema.json +143 -0
  11. package/.cerebro/schemas/team-run.schema.json +234 -0
  12. package/.cerebro/schemas/upgrade-manifest.schema.json +45 -0
  13. package/.cerebro/schemas/upgrade-state.schema.json +38 -0
  14. package/.cerebro/scripts/check-agent-teams-enabled.py +24 -0
  15. package/.cerebro/scripts/ensure-upgrade-cache-gitignored.py +27 -0
  16. package/.cerebro/scripts/fetch-upstream-ref.py +67 -0
  17. package/.cerebro/scripts/reset-runtime.py +125 -0
  18. package/.cerebro/scripts/setup-status.py +101 -0
  19. package/.cerebro/scripts/test-stop-hook.py +60 -0
  20. package/.cerebro/scripts/upgrade-latest-tag.py +34 -0
  21. package/.cerebro/scripts/validate-agent-frontmatter.py +87 -0
  22. package/.cerebro/scripts/validate-boulder.py +105 -0
  23. package/.cerebro/scripts/validate-opencode-runtime.py +94 -0
  24. package/.cerebro/scripts/validate-team-runs.py +310 -0
  25. package/.cerebro/scripts/validate-upgrade-metadata.py +104 -0
  26. package/.cerebro/scripts/write-upgrade-state.py +93 -0
  27. package/.cerebro/templates/customer-vision.md +58 -0
  28. package/.cerebro/templates/plan.md +35 -0
  29. package/.cerebro/templates/product-brief.md +110 -0
  30. package/.cerebro/templates/project-context.md +64 -0
  31. package/.cerebro/templates/requirements-brief.md +67 -0
  32. package/.cerebro/templates/team-run.json +22 -0
  33. package/.cerebro/upgrade-manifest.json +160 -0
  34. package/.opencode/.gitignore +5 -0
  35. package/.opencode/agents/beast.md +38 -0
  36. package/.opencode/agents/cerebro.md +22 -0
  37. package/.opencode/agents/cyclops.md +22 -0
  38. package/.opencode/agents/cypher.md +46 -0
  39. package/.opencode/agents/emma-frost.md +38 -0
  40. package/.opencode/agents/forge.md +22 -0
  41. package/.opencode/agents/legion.md +45 -0
  42. package/.opencode/agents/nightcrawler.md +22 -0
  43. package/.opencode/agents/professor-x.md +39 -0
  44. package/.opencode/agents/sage.md +22 -0
  45. package/.opencode/agents/storm.md +49 -0
  46. package/.opencode/agents/wolverine.md +22 -0
  47. package/.opencode/commands/cerebro-doctor.md +19 -0
  48. package/.opencode/commands/cerebro-index.md +22 -0
  49. package/.opencode/commands/cerebro-plan.md +21 -0
  50. package/.opencode/commands/cerebro-reset.md +20 -0
  51. package/.opencode/commands/cerebro-start-work.md +20 -0
  52. package/.opencode/commands/cerebro-upgrade.md +19 -0
  53. package/.opencode/commands/to-me-my-x-men.md +27 -0
  54. package/AGENTS.md +12 -0
  55. package/README.md +193 -0
  56. package/dist/cli.d.ts +2 -0
  57. package/dist/cli.js +597 -0
  58. package/dist/index.d.ts +4 -0
  59. package/dist/index.js +466 -0
  60. package/package.json +54 -0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env python3
2
+ """Validate Cerebro upgrade manifest and upgrade state metadata."""
3
+
4
+ import json
5
+ import re
6
+ from pathlib import Path
7
+
8
+
9
+ VALID_OWNERSHIPS = {"template", "merge", "user"}
10
+ SHA_RE = re.compile(r"^[0-9a-f]{40}$")
11
+
12
+
13
+ def main() -> int:
14
+ errors = []
15
+ errors.extend(validate_json_file(Path(".cerebro/schemas/upgrade-manifest.schema.json")))
16
+ errors.extend(validate_json_file(Path(".cerebro/schemas/upgrade-state.schema.json")))
17
+ errors.extend(validate_manifest())
18
+ errors.extend(validate_state())
19
+
20
+ if errors:
21
+ for error in errors:
22
+ print(error)
23
+ return 1
24
+
25
+ return 0
26
+
27
+
28
+ def validate_json_file(path: Path) -> list[str]:
29
+ if not path.exists():
30
+ return [f"{path} missing"]
31
+ try:
32
+ json.loads(path.read_text(encoding="utf-8"))
33
+ except json.JSONDecodeError as exc:
34
+ return [f"{path} invalid JSON: {exc}"]
35
+ print(f"{path.name} valid")
36
+ return []
37
+
38
+
39
+ def validate_manifest() -> list[str]:
40
+ manifest_path = Path(".cerebro/upgrade-manifest.json")
41
+ if not manifest_path.exists():
42
+ print("no manifest present (informational - run /cerebro-upgrade to initialize)")
43
+ return []
44
+
45
+ try:
46
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
47
+ except json.JSONDecodeError as exc:
48
+ return [f"upgrade-manifest.json invalid JSON: {exc}"]
49
+ errors = []
50
+ entries = manifest.get("entries", [])
51
+ if not isinstance(entries, list) or not entries:
52
+ errors.append("entries must be a non-empty array")
53
+ return errors
54
+
55
+ for index, entry in enumerate(entries):
56
+ if not isinstance(entry, dict):
57
+ errors.append(f"entry {index}: must be an object")
58
+ continue
59
+ if "path" not in entry:
60
+ errors.append(f"entry {index}: missing 'path'")
61
+ if "ownership" not in entry:
62
+ errors.append(f"entry {index}: missing 'ownership'")
63
+ elif entry["ownership"] not in VALID_OWNERSHIPS:
64
+ errors.append(
65
+ f"entry {index}: invalid ownership '{entry['ownership']}' "
66
+ "(must be template, merge, or user)"
67
+ )
68
+
69
+ if not errors:
70
+ print(f"manifest entries ok ({len(entries)} entries)")
71
+ return errors
72
+
73
+
74
+ def validate_state() -> list[str]:
75
+ state_path = Path(".cerebro/upgrade-state.json")
76
+ if not state_path.exists():
77
+ print("no upgrade-state.json present (informational - will be written after first /cerebro-upgrade)")
78
+ return []
79
+
80
+ try:
81
+ state = json.loads(state_path.read_text(encoding="utf-8"))
82
+ except json.JSONDecodeError as exc:
83
+ return [f"upgrade-state.json invalid JSON: {exc}"]
84
+ errors = []
85
+ required = {"version", "applied_ref", "applied_sha", "applied_at", "hashes"}
86
+ missing = sorted(required - set(state))
87
+ if missing:
88
+ errors.append(f"upgrade-state.json missing fields: {missing}")
89
+ if state.get("version") != 1:
90
+ errors.append(f"unexpected version: {state.get('version')}")
91
+
92
+ sha = state.get("applied_sha", "")
93
+ if not SHA_RE.match(sha):
94
+ errors.append(f"applied_sha is not a 40-char hex: {sha!r}")
95
+ if not isinstance(state.get("hashes"), dict):
96
+ errors.append("hashes must be an object")
97
+
98
+ if not errors:
99
+ print(f"upgrade-state.json valid (ref={state['applied_ref']}, sha={sha[:8]}...)")
100
+ return errors
101
+
102
+
103
+ if __name__ == "__main__":
104
+ raise SystemExit(main())
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python3
2
+ """Atomically write .cerebro/upgrade-state.json from current owned file hashes."""
3
+
4
+ import argparse
5
+ import fnmatch
6
+ import hashlib
7
+ import json
8
+ import tempfile
9
+ from datetime import datetime, timezone
10
+ from pathlib import Path
11
+
12
+
13
+ OWNED_FOR_BASELINE = {"template", "merge"}
14
+
15
+
16
+ def main() -> int:
17
+ parser = argparse.ArgumentParser(description=__doc__)
18
+ parser.add_argument("--ref", required=True, dest="applied_ref")
19
+ parser.add_argument("--sha", required=True, dest="applied_sha")
20
+ parser.add_argument("--manifest", default=".cerebro/upgrade-manifest.json")
21
+ parser.add_argument("--output", default=".cerebro/upgrade-state.json")
22
+ args = parser.parse_args()
23
+
24
+ manifest_path = Path(args.manifest)
25
+ if not manifest_path.exists():
26
+ print(f"manifest not found: {manifest_path}")
27
+ return 1
28
+
29
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
30
+ hashes = collect_hashes(manifest)
31
+ state = {
32
+ "version": 1,
33
+ "applied_ref": args.applied_ref,
34
+ "applied_sha": args.applied_sha,
35
+ "applied_at": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
36
+ "hashes": hashes,
37
+ }
38
+
39
+ output = Path(args.output)
40
+ output.parent.mkdir(parents=True, exist_ok=True)
41
+ with tempfile.NamedTemporaryFile(
42
+ "w",
43
+ encoding="utf-8",
44
+ dir=output.parent,
45
+ prefix=output.stem + ".",
46
+ suffix=".tmp",
47
+ delete=False,
48
+ ) as handle:
49
+ json.dump(state, handle, indent=2, sort_keys=True)
50
+ handle.write("\n")
51
+ tmp_path = Path(handle.name)
52
+ tmp_path.replace(output)
53
+ print(f"wrote {output} with {len(hashes)} file hash(es)")
54
+ return 0
55
+
56
+
57
+ def collect_hashes(manifest: dict) -> dict[str, str]:
58
+ paths = set()
59
+ for entry in manifest.get("entries", []):
60
+ if entry.get("ownership") not in OWNED_FOR_BASELINE:
61
+ continue
62
+ pattern = entry.get("path")
63
+ if not pattern:
64
+ continue
65
+ paths.update(expand_pattern(pattern))
66
+
67
+ return {path: sha256(Path(path)) for path in sorted(paths) if Path(path).is_file()}
68
+
69
+
70
+ def expand_pattern(pattern: str) -> set[str]:
71
+ if not _has_glob(pattern):
72
+ return {pattern} if Path(pattern).is_file() else set()
73
+ return {
74
+ str(path)
75
+ for path in Path(".").rglob("*")
76
+ if path.is_file() and fnmatch.fnmatch(str(path).removeprefix("./"), pattern)
77
+ }
78
+
79
+
80
+ def sha256(path: Path) -> str:
81
+ digest = hashlib.sha256()
82
+ with path.open("rb") as handle:
83
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
84
+ digest.update(chunk)
85
+ return digest.hexdigest()
86
+
87
+
88
+ def _has_glob(pattern: str) -> bool:
89
+ return any(char in pattern for char in "*?[")
90
+
91
+
92
+ if __name__ == "__main__":
93
+ raise SystemExit(main())
@@ -0,0 +1,58 @@
1
+ # [Product Name] — Customer Vision & Acceptance
2
+
3
+ **Voice:** Legion (Customer / Product-Owner proxy)
4
+ **Request:** [The user's original request, verbatim or lightly cleaned.]
5
+
6
+ ## The Customer's Premise
7
+
8
+ [2–3 sentences in the customer's voice: what I'm trying to do and why I care. The mindset of the person this is for.]
9
+
10
+ ## Personas
11
+
12
+ For each distinct user this product must satisfy:
13
+
14
+ ### [Persona name]
15
+
16
+ - **Context:** [Who they are, when/where/why they reach for this.]
17
+ - **What delights them:** [What makes them love it.]
18
+ - **What makes them bounce:** [Friction or absence that makes them quit.]
19
+ - **Will not tolerate:** [Hard deal-breakers.]
20
+
21
+ ## Must-Haves (non-negotiable)
22
+
23
+ - [Capability or quality the product cannot ship without.]
24
+
25
+ ## Deal-Breakers
26
+
27
+ - [Things that, if present or missing, mean I reject the product outright.]
28
+
29
+ ## Quality Bar — "Great, Not Generic"
30
+
31
+ What separates a product I'd recommend from a forgettable demo:
32
+
33
+ - **Experience:** [What the core flow must feel like.]
34
+ - **Polish:** [The finish that signals craft.]
35
+ - **Completeness:** [States and edges a real user hits that must be handled.]
36
+
37
+ ## Competitive Expectations
38
+
39
+ Grounded in real products in this space (from research):
40
+
41
+ - **[Product / pattern]** — [What it does well that sets my expectation] — [source]
42
+
43
+ ## Success In One Sentence
44
+
45
+ > [The customer's own definition of "this works and I'd use it."]
46
+
47
+ ---
48
+
49
+ ## Acceptance Record (filled in Mode 2, end of build)
50
+
51
+ **Verdict:** ACCEPT | REJECT | (pending)
52
+ **Would I use this:** [one honest sentence]
53
+
54
+ **Gaps found:**
55
+ - [As a {persona}: what broke the experience — what good requires — where it fell short, or None]
56
+
57
+ **Genuinely good:**
58
+ - [Earned praise, or None yet]
@@ -0,0 +1,35 @@
1
+ # [Plan Name]
2
+
3
+ **Objective:** [One sentence describing the user-visible change.]
4
+ **Risk Level:** LOW | MEDIUM | HIGH
5
+
6
+ ## Assumptions and Decisions
7
+
8
+ - [Decision or assumption that affects implementation.]
9
+
10
+ ## Approval Gates
11
+
12
+ - [ ] None
13
+
14
+ Use explicit gates for destructive, irreversible, privileged, external mutating, production, data, auth, billing, dependency-upgrade, or git-history actions.
15
+
16
+ ## Acceptance Criteria
17
+
18
+ - [ ] [Concrete pass/fail criterion.]
19
+ - [ ] [Concrete pass/fail criterion.]
20
+
21
+ ## Tasks
22
+
23
+ ### Task 1: [Name]
24
+
25
+ **Owner:** Wolverine | Storm | Cyclops | Forge consultation
26
+ **Files:** `[exact/path.ext]` (modify/create) or `None`
27
+ **What:** [Specific implementation or verification action.]
28
+ **TDD:** [Failing test to write first, or "Not applicable: [reason]".]
29
+ **Verify:** `[exact command or manual check]`
30
+ **Risk:** LOW | MEDIUM | HIGH
31
+ **Approval Gate:** None | [Gate name from Approval Gates]
32
+
33
+ ## Rollback / Recovery
34
+
35
+ - [How to undo or recover if execution fails. Use "Not applicable" only for low-risk docs/config-only work.]
@@ -0,0 +1,110 @@
1
+ # [Product Name] — Product Brief
2
+
3
+ **Objective:** [One sentence: what is being built and for whom.]
4
+ **Mission Shape:** PRODUCT_BUILD | BOUNDED | RESEARCH_ONLY
5
+ **Risk Level:** LOW | MEDIUM | HIGH
6
+
7
+ ## Objective and Target User
8
+
9
+ - **Primary user:** [Who they are.]
10
+ - **Core job-to-be-done:** [The one job this product must nail.]
11
+
12
+ ## Assumptions and Non-Goals
13
+
14
+ **Assumptions** (every material choice made without explicit user input):
15
+
16
+ - [Assumption — why it is conservative/reversible.]
17
+
18
+ **Non-goals** (explicitly NOT being built):
19
+
20
+ - [Non-goal.]
21
+
22
+ ## Tech Stack Decision Log
23
+
24
+ | Concern | Choice | Rationale |
25
+ |---|---|---|
26
+ | Framework | [choice] | [why — reference §6.5 defaults where applied] |
27
+ | Language | [choice] | [why] |
28
+ | Styling | [choice] | [why] |
29
+ | Database / persistence | [choice] | [why] |
30
+ | ORM | [choice] | [why] |
31
+ | Auth | [choice] | [why] |
32
+ | Testing | [choice] | [why] |
33
+
34
+ ## Screens / Routes / API Surfaces
35
+
36
+ - `[route or surface]` — [purpose]
37
+
38
+ ## Core User Flows
39
+
40
+ ### Flow 1: [Name]
41
+
42
+ 1. [Step — happy path.]
43
+ 2. [Step.]
44
+
45
+ **Failure paths:** [What happens on error / invalid input / timeout.]
46
+
47
+ ## Design Direction (greenfield UI)
48
+
49
+ - **Chosen direction:** [typography, color system, layout language, mood.]
50
+ - **Why it won:** [over which alternatives.]
51
+
52
+ ## UX / Screen Spec
53
+
54
+ ### [Screen name] (`[route]`)
55
+
56
+ - **Layout:** [description]
57
+ - **Components:** [list]
58
+ - **States:** loading / error / empty / populated — [each described]
59
+ - **Responsive:** [behavior at mobile / desktop]
60
+ - **Navigation:** [entry and exit points]
61
+
62
+ ## Data Model
63
+
64
+ - **[Entity]** — [key fields, relationships]
65
+
66
+ **Migration strategy:** [approach]
67
+
68
+ ## Security Model
69
+
70
+ - **Auth strategy:** [sessions/JWT, storage, expiry]
71
+ - **Input validation:** [approach, library]
72
+ - **CORS policy:** [policy]
73
+ - **Secrets:** [where they live, how they are loaded]
74
+
75
+ ## Environment Variable Manifest
76
+
77
+ | Name | Purpose | Example | Required |
78
+ |---|---|---|---|
79
+ | `[VAR]` | [purpose] | `[example]` | yes/no |
80
+
81
+ ## Architecture and File Ownership Map
82
+
83
+ ```
84
+ [directory structure]
85
+ ```
86
+
87
+ | Area | Owner |
88
+ |---|---|
89
+ | `[path]` | wolverine-1 \| wolverine-2 \| storm-ui |
90
+
91
+ ## Milestones
92
+
93
+ ### Milestone 1: [Name]
94
+
95
+ - **Acceptance criteria:** [concrete, measurable — not "it works correctly"]
96
+ - **Verify:** `[exact command or manual check]`
97
+
98
+ ## Tests and Verification Commands
99
+
100
+ - `[command]` — [what passing means]
101
+
102
+ ## Production Readiness Criteria
103
+
104
+ - [§9.5 checklist items that apply to this build.]
105
+
106
+ ## Risks, Approval Gates, Rollback
107
+
108
+ - **Risks:** [risk — mitigation]
109
+ - **Approval gates:** [gate, or None]
110
+ - **Rollback / recovery:** [how to undo if execution fails]
@@ -0,0 +1,64 @@
1
+ # Cerebro Project Context
2
+
3
+ **Indexed At:** [timestamp]
4
+ **Repository:** [name or path]
5
+
6
+ ## Stack
7
+
8
+ - Language/runtime:
9
+ - Frameworks:
10
+ - Package manager:
11
+ - Test framework:
12
+ - Build system:
13
+
14
+ ## Entrypoints
15
+
16
+ - Plugin/source:
17
+ - CLI/scripts:
18
+ - OpenCode agents:
19
+ - OpenCode commands:
20
+ - Runtime state:
21
+ - Configuration:
22
+
23
+ ## Commands
24
+
25
+ - Install:
26
+ - Test:
27
+ - Focused test:
28
+ - Lint:
29
+ - Typecheck:
30
+ - Build:
31
+ - Run/dev:
32
+
33
+ ## Architecture
34
+
35
+ - [Major subsystem] - [purpose and relevant files]
36
+ - [Major subsystem] - [purpose and relevant files]
37
+ - `.opencode/` - active OpenCode agents, commands, and plugin bridge when this is an OpenCode/Cerebro project
38
+ - `.cerebro/` - plans, run manifests, task ledgers, mailbox logs, checkpoints, notepads, and validators
39
+
40
+ ## Conventions
41
+
42
+ - File organization:
43
+ - Naming:
44
+ - Error handling:
45
+ - Testing:
46
+ - Model routing:
47
+ - UI/styling:
48
+
49
+ ## Risky Areas
50
+
51
+ - [Area] - [why risky and what to verify]
52
+
53
+ ## Agent Notes
54
+
55
+ - Prefer:
56
+ - Avoid:
57
+ - Open questions:
58
+
59
+ ## Read First
60
+
61
+ 1. `AGENTS.md` - repository-level operating rules, if present
62
+ 2. `.cerebro/cerebro-identity.md` - Cerebro runtime identity and role routing, if present
63
+ 3. `.cerebro/opencode/model-routing.md` - OpenCode model slots, if present
64
+ 4. Relevant `.opencode/agents/*.md` and `.opencode/commands/*.md`, if present
@@ -0,0 +1,67 @@
1
+ # [Product Name] — Requirements Brief
2
+
3
+ **Prepared by:** Cypher (Business Analyst)
4
+ **Request:** [The user's original request, verbatim or lightly cleaned.]
5
+ **Mission Shape:** PRODUCT_BUILD | BOUNDED | RESEARCH_ONLY
6
+
7
+ ## Problem Statement
8
+
9
+ [2–3 sentences: what problem this solves and why it matters. The WHY behind the request.]
10
+
11
+ ## Target Users
12
+
13
+ - **Primary user:** [Who they are, their context, their level of expertise.]
14
+ - **Secondary users:** [If any, or None.]
15
+
16
+ ## Jobs To Be Done
17
+
18
+ - **Core job:** [The one job this product must nail — "When ___, I want to ___, so I can ___".]
19
+ - **Supporting jobs:** [Other jobs, ranked.]
20
+
21
+ ## User Stories
22
+
23
+ | # | As a… | I want to… | So that… | Priority |
24
+ |---|---|---|---|---|
25
+ | 1 | [user] | [action] | [outcome] | must / should / could |
26
+
27
+ ## Acceptance Criteria
28
+
29
+ Per story or per capability — concrete, testable, pass/fail (never "it works correctly"):
30
+
31
+ - **Story 1:**
32
+ - [ ] [Given … when … then …]
33
+ - [ ] [Edge case: empty / error / boundary behavior]
34
+
35
+ ## Business Rules
36
+
37
+ - [Rule the product must enforce — validation, limits, permissions, state transitions.]
38
+
39
+ ## Success Metrics
40
+
41
+ - [How we know the product succeeds — measurable where possible.]
42
+
43
+ ## Scope
44
+
45
+ **In scope:**
46
+ - [Capability.]
47
+
48
+ **Out of scope / non-goals:**
49
+ - [Explicitly NOT being built.]
50
+
51
+ ## Assumptions
52
+
53
+ Conservative, reversible choices made without explicit user input:
54
+
55
+ - [Assumption — why it is safe.]
56
+
57
+ ## Open Questions
58
+
59
+ **Blocking (need a user/Cerebro decision before build):**
60
+ - [Question, or None.]
61
+
62
+ **Non-blocking (safe to proceed, worth confirming):**
63
+ - [Question, or None.]
64
+
65
+ ## Handoff to Professor X
66
+
67
+ [One paragraph: the essence Professor X needs to design the technical Product Brief. Points him at the must-have stories and the hardest acceptance criteria. Does NOT prescribe HOW.]
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 1,
3
+ "run_id": "20260522-000000-example-run",
4
+ "command": "/to-me-my-x-men",
5
+ "status": "planning",
6
+ "lead": "cerebro",
7
+ "team_name": "replace-with-team-name",
8
+ "objective": "replace with the user objective",
9
+ "risk_level": "LOW",
10
+ "started_at": "2026-05-22T00:00:00Z",
11
+ "updated_at": "2026-05-22T00:00:00Z",
12
+ "teammates": [],
13
+ "ownership": [],
14
+ "mailbox_decisions": [],
15
+ "approvals": [],
16
+ "verification": [],
17
+ "cleanup": {
18
+ "team_stopped": false,
19
+ "pending_todos_clear": false,
20
+ "notes": ""
21
+ }
22
+ }