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.
- package/.cerebro/.gitignore +27 -0
- package/.cerebro/cerebro-identity.md +76 -0
- package/.cerebro/docs/agent-mapping.md +54 -0
- package/.cerebro/docs/cerebro-workflow.md +115 -0
- package/.cerebro/docs/orchestration.md +28 -0
- package/.cerebro/docs/overview.md +44 -0
- package/.cerebro/docs/skill-policy.md +25 -0
- package/.cerebro/integrations/semble.md +30 -0
- package/.cerebro/opencode/model-routing.md +37 -0
- package/.cerebro/schemas/boulder.schema.json +143 -0
- package/.cerebro/schemas/team-run.schema.json +234 -0
- package/.cerebro/schemas/upgrade-manifest.schema.json +45 -0
- package/.cerebro/schemas/upgrade-state.schema.json +38 -0
- package/.cerebro/scripts/check-agent-teams-enabled.py +24 -0
- package/.cerebro/scripts/ensure-upgrade-cache-gitignored.py +27 -0
- package/.cerebro/scripts/fetch-upstream-ref.py +67 -0
- package/.cerebro/scripts/reset-runtime.py +125 -0
- package/.cerebro/scripts/setup-status.py +101 -0
- package/.cerebro/scripts/test-stop-hook.py +60 -0
- package/.cerebro/scripts/upgrade-latest-tag.py +34 -0
- package/.cerebro/scripts/validate-agent-frontmatter.py +87 -0
- package/.cerebro/scripts/validate-boulder.py +105 -0
- package/.cerebro/scripts/validate-opencode-runtime.py +94 -0
- package/.cerebro/scripts/validate-team-runs.py +310 -0
- package/.cerebro/scripts/validate-upgrade-metadata.py +104 -0
- package/.cerebro/scripts/write-upgrade-state.py +93 -0
- package/.cerebro/templates/customer-vision.md +58 -0
- package/.cerebro/templates/plan.md +35 -0
- package/.cerebro/templates/product-brief.md +110 -0
- package/.cerebro/templates/project-context.md +64 -0
- package/.cerebro/templates/requirements-brief.md +67 -0
- package/.cerebro/templates/team-run.json +22 -0
- package/.cerebro/upgrade-manifest.json +160 -0
- package/.opencode/.gitignore +5 -0
- package/.opencode/agents/beast.md +38 -0
- package/.opencode/agents/cerebro.md +22 -0
- package/.opencode/agents/cyclops.md +22 -0
- package/.opencode/agents/cypher.md +46 -0
- package/.opencode/agents/emma-frost.md +38 -0
- package/.opencode/agents/forge.md +22 -0
- package/.opencode/agents/legion.md +45 -0
- package/.opencode/agents/nightcrawler.md +22 -0
- package/.opencode/agents/professor-x.md +39 -0
- package/.opencode/agents/sage.md +22 -0
- package/.opencode/agents/storm.md +49 -0
- package/.opencode/agents/wolverine.md +22 -0
- package/.opencode/commands/cerebro-doctor.md +19 -0
- package/.opencode/commands/cerebro-index.md +22 -0
- package/.opencode/commands/cerebro-plan.md +21 -0
- package/.opencode/commands/cerebro-reset.md +20 -0
- package/.opencode/commands/cerebro-start-work.md +20 -0
- package/.opencode/commands/cerebro-upgrade.md +19 -0
- package/.opencode/commands/to-me-my-x-men.md +27 -0
- package/AGENTS.md +12 -0
- package/README.md +193 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +597 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +466 -0
- 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
|
+
}
|