pantheon-opencode 1.5.2 → 1.6.0-beta.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 (60) hide show
  1. package/.pantheon/code-mode/README.md +4 -2
  2. package/.pantheon/code-mode/checkpoint_session.py +138 -102
  3. package/.pantheon/code-mode/compress-inline.py +102 -57
  4. package/.pantheon/code-mode/manifest.json +2 -8
  5. package/CHANGELOG.md +17 -0
  6. package/README.md +86 -52
  7. package/README.pt-BR.md +63 -43
  8. package/commands/pantheon-optimize.md +2 -2
  9. package/package.json +13 -1
  10. package/plugin.json +1 -1
  11. package/pyproject.toml +8 -15
  12. package/scripts/build-agents-md.mjs +2 -2
  13. package/scripts/check-plugin-v2-coverage.mjs +213 -0
  14. package/scripts/ci-validate-yaml.py +7 -5
  15. package/scripts/code_mode_server.py +116 -24
  16. package/scripts/doctor.mjs +85 -28
  17. package/scripts/install/cli-ui.mjs +1 -1
  18. package/scripts/install/config-migration.mjs +2 -2
  19. package/scripts/install/health-check.mjs +6 -19
  20. package/scripts/install/interactive.mjs +6 -6
  21. package/scripts/install/migrate.mjs +1 -1
  22. package/scripts/mcp_persistence_server.py +390 -76
  23. package/scripts/memory_mcp_server.py +370 -196
  24. package/scripts/postinstall.mjs +0 -7
  25. package/scripts/probe-context-rehydrate.mjs +28 -11
  26. package/scripts/prune.mjs +2 -2
  27. package/scripts/test-opencode-v2-sandbox.sh +1759 -0
  28. package/scripts/validate-routing.mjs +40 -0
  29. package/skills-lock.json +9 -10
  30. package/src/agents/mnemosyne.md +15 -16
  31. package/src/agents/zeus.md +1 -2
  32. package/src/mcp/code_mode_server.py +116 -24
  33. package/src/mcp/mcp_codemap_module.py +559 -129
  34. package/src/mcp/mcp_persistence_server.py +390 -76
  35. package/src/mcp/memory_mcp_server.py +371 -248
  36. package/src/mcp/pantheon_vision_server.py +136 -24
  37. package/src/mcp/requirements-mcp.txt +5 -3
  38. package/src/mcp/requirements-vision.txt +2 -0
  39. package/src/pantheon/model-command.ts +18 -7
  40. package/src/pantheon/todo-enforcer.ts +1 -1
  41. package/src/pantheon/vision.ts +1 -1
  42. package/src/plugin-v2.ts +134 -104
  43. package/src/plugins/tui/dist/tui.js +1 -1
  44. package/src/plugins/tui/package-lock.json +20 -20
  45. package/src/plugins/tui/package.json +12 -12
  46. package/src/routing.yml +0 -1
  47. package/src/skills/README.md +31 -36
  48. package/src/skills/auto-continue/SKILL.md +25 -75
  49. package/.pantheon/code-mode/eval-llm-judge.py +0 -255
  50. package/.pantheon/code-mode/eval-monte-carlo.py +0 -368
  51. package/.pantheon/code-mode/eval-run.py +0 -197
  52. package/.pantheon/code-mode/eval-static.py +0 -321
  53. package/.pantheon/code-mode/session-end-save.py +0 -186
  54. package/.pantheon/code-mode/session-end-save.sh +0 -18
  55. package/scripts/recover-zenodo-deposition.mjs +0 -146
  56. package/scripts/test-opencode-v1-v2-sandbox.sh +0 -862
  57. package/scripts/validate-zenodo-release.mjs +0 -154
  58. package/scripts/zenodo-artifact.mjs +0 -94
  59. package/scripts/zenodo-release-state.mjs +0 -53
  60. package/src/skills/orchestration-workflow/SKILL.md +0 -311
@@ -1,154 +0,0 @@
1
- #!/usr/bin/env node
2
- /** Validate the immutable inputs used by the GitHub Release → Zenodo workflow. */
3
-
4
- import { existsSync, readFileSync } from 'node:fs'
5
- import { join } from 'node:path'
6
- import { pathToFileURL } from 'node:url'
7
- import { compareVersions } from './version-check.mjs'
8
-
9
- const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
10
-
11
- function validateHttpsUrl(value, name) {
12
- let url
13
- try {
14
- url = new URL(value)
15
- } catch {
16
- throw new Error(`${name} must be an absolute HTTPS URL.`)
17
- }
18
- if (
19
- url.protocol !== 'https:' ||
20
- !url.hostname ||
21
- url.username ||
22
- url.password ||
23
- /%(?![0-9A-Fa-f]{2})/.test(value) ||
24
- /[\s{}\\|^`]/.test(value)
25
- ) {
26
- throw new Error(`${name} must be an absolute HTTPS URL without credentials.`)
27
- }
28
- return url
29
- }
30
-
31
- function maskHost(hostname) {
32
- if (hostname.length <= 2) return '***'
33
- return `${hostname[0]}***${hostname.at(-1)}`
34
- }
35
-
36
- export function summarizeZenodoConfiguration({
37
- depositionsUrl,
38
- filesUrlTemplate,
39
- publishUrlTemplate,
40
- creatorName,
41
- }) {
42
- const values = [
43
- ['ZENODO_DEPOSITIONS_URL', depositionsUrl, true],
44
- ['ZENODO_FILES_URL_TEMPLATE', filesUrlTemplate, true],
45
- ['ZENODO_PUBLISH_URL_TEMPLATE', publishUrlTemplate, true],
46
- ['ZENODO_CREATOR_NAME', creatorName, false],
47
- ]
48
- return values.map(([name, value, isUrl]) => {
49
- if (typeof value !== 'string' || !value) return { name, present: false }
50
- if (!isUrl) return { name, present: true }
51
- try {
52
- const url = new URL(value.replaceAll('{id}', '1'))
53
- return {
54
- name,
55
- present: true,
56
- protocol: url.protocol,
57
- host: maskHost(url.hostname),
58
- hasWhitespace: /\s/.test(value),
59
- hasCredentials: Boolean(url.username || url.password),
60
- }
61
- } catch {
62
- return {
63
- name,
64
- present: true,
65
- protocol: 'invalid',
66
- host: '***',
67
- hasWhitespace: /\s/.test(value),
68
- }
69
- }
70
- })
71
- }
72
-
73
- export function zenodoTemplateUrl(template, id, name = 'Zenodo URL template') {
74
- if (!Number.isSafeInteger(id) || id <= 0) throw new Error('Zenodo deposition id is invalid.')
75
- if (typeof template !== 'string' || !template.includes('{id}'))
76
- throw new Error(`${name} must contain the {id} placeholder.`)
77
- return validateHttpsUrl(template.replaceAll('{id}', String(id)), name).href
78
- }
79
-
80
- export function zenodoDepositionUrl(depositionsUrl, id) {
81
- if (!Number.isSafeInteger(id) || id <= 0) throw new Error('Zenodo deposition id is invalid.')
82
- if (typeof depositionsUrl !== 'string')
83
- throw new Error('ZENODO_DEPOSITIONS_URL must be an absolute HTTPS URL.')
84
- const base = validateHttpsUrl(depositionsUrl, 'ZENODO_DEPOSITIONS_URL')
85
- if (base.search || base.hash)
86
- throw new Error('ZENODO_DEPOSITIONS_URL must not contain a query or fragment.')
87
- return new URL(`${base.pathname.replace(/\/$/, '')}/${id}`, base.origin).href
88
- }
89
-
90
- export function validateZenodoConfiguration({
91
- depositionsUrl,
92
- filesUrlTemplate,
93
- publishUrlTemplate,
94
- creatorName,
95
- }) {
96
- const base = validateHttpsUrl(depositionsUrl, 'ZENODO_DEPOSITIONS_URL')
97
- for (const [name, template] of [
98
- ['ZENODO_FILES_URL_TEMPLATE', filesUrlTemplate],
99
- ['ZENODO_PUBLISH_URL_TEMPLATE', publishUrlTemplate],
100
- ]) {
101
- if (
102
- typeof template !== 'string' ||
103
- !template.includes('{id}') ||
104
- template.replaceAll('{id}', '').match(/[{}]/) ||
105
- template.includes('{{') ||
106
- template.includes('}}')
107
- ) {
108
- throw new Error(`${name} must be an HTTPS URL template containing the {id} placeholder.`)
109
- }
110
- const url = new URL(zenodoTemplateUrl(template, 1, name))
111
- if (url.origin !== base.origin) throw new Error(`${name} must use the Zenodo depositions host.`)
112
- }
113
- if (typeof creatorName !== 'string' || !creatorName.trim())
114
- throw new Error('ZENODO_CREATOR_NAME must not be empty.')
115
- return true
116
- }
117
-
118
- export function validateZenodoRelease(root, tag) {
119
- if (!/^v/.test(tag)) throw new Error('Release tag must start with v.')
120
- const version = tag.slice(1)
121
- if (!SEMVER.test(version)) throw new Error('Release tag is not valid semver.')
122
- const packageJson = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
123
- if (packageJson.name !== 'pantheon-opencode' || packageJson.version !== version) {
124
- throw new Error('Release tag does not match package.json.')
125
- }
126
- const manifests = compareVersions(root)
127
- if (!manifests.ok) throw new Error('Release manifests are out of sync.')
128
- const citationPath = join(root, 'CITATION.cff')
129
- const citation = { present: existsSync(citationPath), version: null }
130
- if (citation.present) {
131
- const match = readFileSync(citationPath, 'utf8').match(/^version:\s*["']?([^"'\s]+)["']?\s*$/m)
132
- if (!match) throw new Error('CITATION.cff is missing its version field.')
133
- citation.version = match[1]
134
- if (citation.version !== version)
135
- throw new Error('CITATION.cff version differs from the release tag.')
136
- }
137
- return { tag, version, citation }
138
- }
139
-
140
- const isDirectRun = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href
141
- if (isDirectRun) {
142
- try {
143
- validateZenodoConfiguration({
144
- depositionsUrl: process.env.ZENODO_DEPOSITIONS_URL,
145
- filesUrlTemplate: process.env.ZENODO_FILES_URL_TEMPLATE,
146
- publishUrlTemplate: process.env.ZENODO_PUBLISH_URL_TEMPLATE,
147
- creatorName: process.env.ZENODO_CREATOR_NAME,
148
- })
149
- console.log(JSON.stringify(validateZenodoRelease(process.cwd(), process.env.RELEASE_TAG ?? '')))
150
- } catch (error) {
151
- console.error(`zenodo validation: ${error.message}`)
152
- process.exit(1)
153
- }
154
- }
@@ -1,94 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
- import { readFileSync } from 'node:fs'
3
-
4
- /** Hex digest length for every algorithm the Zenodo deposition API may report. */
5
- const DIGEST_LENGTH = { md5: 32, sha256: 64 }
6
-
7
- export function sha256File(path) {
8
- return createHash('sha256').update(readFileSync(path)).digest('hex')
9
- }
10
-
11
- export function md5File(path) {
12
- return createHash('md5').update(readFileSync(path)).digest('hex')
13
- }
14
-
15
- /**
16
- * Normalize a file checksum as returned by the Zenodo deposition files API.
17
- *
18
- * Zenodo computes an MD5 for every deposited file (developers.zenodo.org,
19
- * "Deposition File" representation: "MD5 checksum of file, computed by our
20
- * system"). The API emits it both as `md5:<hex>` and, because of a legacy
21
- * serialization bug kept for backward compatibility (zenodo/zenodo#628), as a
22
- * bare 32-character hex string without any algorithm prefix — the exact payload
23
- * that broke the v1.5.1 run (e.g. `d3359dca2f998da8461abb3b84a32b6c`).
24
- *
25
- * A bare 64-character digest is treated as SHA-256, so if the API ever upgrades
26
- * its algorithm the upload is still verified with a strong digest rather than
27
- * accepted blindly. Anything unrecognized fails closed.
28
- */
29
- export function parseZenodoChecksum(value) {
30
- if (typeof value !== 'string') throw new Error('Zenodo file checksum is missing.')
31
- const match = value
32
- .trim()
33
- .toLowerCase()
34
- .match(/^(?:(md5|sha256):)?([0-9a-f]+)$/)
35
- if (!match) throw new Error(`Unrecognized Zenodo checksum format: ${value}.`)
36
- const algorithm =
37
- match[1] ??
38
- (match[2].length === DIGEST_LENGTH.md5
39
- ? 'md5'
40
- : match[2].length === DIGEST_LENGTH.sha256
41
- ? 'sha256'
42
- : null)
43
- if (!algorithm) throw new Error(`Unrecognized Zenodo checksum length: ${value}.`)
44
- if (match[2].length !== DIGEST_LENGTH[algorithm])
45
- throw new Error(`Zenodo checksum length does not match ${algorithm}: ${value}.`)
46
- return { algorithm, digest: match[2] }
47
- }
48
-
49
- function expectedDigests(expected) {
50
- const provided = {}
51
- if (typeof expected === 'string') {
52
- const { algorithm, digest } = parseZenodoChecksum(expected)
53
- provided[algorithm] = digest
54
- } else if (expected && typeof expected === 'object') {
55
- for (const [algorithm, digest] of Object.entries(expected)) {
56
- if (digest === undefined || digest === null || digest === '') continue
57
- if (!(algorithm in DIGEST_LENGTH))
58
- throw new Error(`Unsupported local checksum algorithm: ${algorithm}.`)
59
- if (
60
- typeof digest !== 'string' ||
61
- !new RegExp(`^[0-9a-f]{${DIGEST_LENGTH[algorithm]}}$`, 'i').test(digest.trim())
62
- )
63
- throw new Error(`Invalid local ${algorithm} checksum for verification.`)
64
- provided[algorithm] = digest.trim().toLowerCase()
65
- }
66
- }
67
- if (Object.keys(provided).length === 0)
68
- throw new Error('A local checksum is required to verify the Zenodo upload.')
69
- return provided
70
- }
71
-
72
- export function findZenodoFile(record, filename, expected) {
73
- if (!record || typeof record !== 'object' || !Array.isArray(record.files)) {
74
- throw new Error('Zenodo record did not contain a files array.')
75
- }
76
- const matches = record.files.filter((file) => file?.filename === filename)
77
- if (matches.length > 1) throw new Error(`Zenodo record contains duplicate file: ${filename}.`)
78
- if (matches.length === 0) return null
79
- const file = matches[0]
80
- const { algorithm, digest } = parseZenodoChecksum(file.checksum)
81
- const provided = expectedDigests(expected)
82
- const reference = provided[algorithm]
83
- if (!reference) {
84
- throw new Error(
85
- `Zenodo reported a ${algorithm} checksum for ${filename} but no local ${algorithm} checksum was provided.`,
86
- )
87
- }
88
- if (digest !== reference) {
89
- throw new Error(
90
- `Zenodo ${algorithm} checksum mismatch for ${filename}: expected ${reference}, received ${digest}.`,
91
- )
92
- }
93
- return file
94
- }
@@ -1,53 +0,0 @@
1
- const DOI_PATTERN = /^10\.\d{4,9}\/\S+$/
2
- const MARKER_PATTERN =
3
- /<!-- zenodo-deposition:(?:id=(\d+);)?(?:doi=([^;\s]+);)?state=(pending|created|published)(?:;claim=([^\s]+))? -->/
4
-
5
- export function extractZenodoDoi(response) {
6
- if (!response || typeof response !== 'object') return null
7
- const candidates = [response.doi, response.metadata?.doi, response.links?.doi]
8
- for (const candidate of candidates) {
9
- if (typeof candidate === 'string' && DOI_PATTERN.test(candidate.trim())) return candidate.trim()
10
- }
11
- return null
12
- }
13
-
14
- export function validateZenodoResponse(response, { requireDoi = false } = {}) {
15
- if (!response || typeof response !== 'object' || Array.isArray(response)) {
16
- throw new Error('Zenodo response must be a JSON object.')
17
- }
18
- if (!Number.isSafeInteger(response.id) || response.id <= 0) {
19
- throw new Error('Zenodo response did not contain a valid deposition id.')
20
- }
21
- const doi = extractZenodoDoi(response)
22
- if (requireDoi && !doi) throw new Error('Zenodo response did not contain a valid DOI.')
23
- return { id: response.id, doi }
24
- }
25
-
26
- export function parseZenodoMarker(body) {
27
- const text = String(body ?? '')
28
- const match = text.match(MARKER_PATTERN)
29
- if (!match) {
30
- const legacy = text.match(/<!-- zenodo-deposition-id:(\d+) -->/)
31
- if (!legacy) return null
32
- const id = Number(legacy[1])
33
- if (!Number.isSafeInteger(id) || id <= 0)
34
- throw new Error('Zenodo marker has an invalid deposition id.')
35
- return { id, doi: null, state: 'created', claim: null }
36
- }
37
- const id = match[1] ? Number(match[1]) : null
38
- if (match[1] && (!Number.isSafeInteger(id) || id <= 0))
39
- throw new Error('Zenodo marker has an invalid deposition id.')
40
- if (match[2] && !DOI_PATTERN.test(match[2])) throw new Error('Zenodo marker has an invalid DOI.')
41
- return { id, doi: match[2] ?? null, state: match[3], claim: match[4] ?? null }
42
- }
43
-
44
- export function zenodoMarker({ id = null, doi = null, state, claim = null }) {
45
- if (!['pending', 'created', 'published'].includes(state))
46
- throw new Error('Zenodo marker state is invalid.')
47
- if (id !== null && (!Number.isSafeInteger(id) || id <= 0))
48
- throw new Error('Zenodo marker id is invalid.')
49
- if (doi !== null && !DOI_PATTERN.test(doi)) throw new Error('Zenodo marker DOI is invalid.')
50
- if (state !== 'pending' && id === null)
51
- throw new Error('Created or published Zenodo markers require an id.')
52
- return `<!-- zenodo-deposition:${id === null ? '' : `id=${id};`}${doi === null ? '' : `doi=${doi};`}state=${state}${claim === null ? '' : `;claim=${claim}`} -->`
53
- }
@@ -1,311 +0,0 @@
1
- ---
2
- name: orchestration-workflow
3
- description: "Practical step-by-step walkthrough for orchestrating features end-to-end using the multi-agent system, from planning through deployment"
4
- context: fork
5
- globs: ["**/AGENTS.md", "**/agents/*.agent.md"]
6
- alwaysApply: false
7
- ---
8
-
9
- # Orchestration Workflow: Step-by-Step Guide
10
-
11
- Practical walkthrough for using the multi-agent system end-to-end. This is your "how-to" guide for orchestrating features from planning through production deployment.
12
-
13
- ---
14
-
15
- ## Your First Feature (Real Example)
16
-
17
- **Scenario:** You want to add JWT authentication to your app.
18
- **Time:** ~6-8 hours total (spread across 1-2 days)
19
- **Team:** All agents working together
20
- **Result:** Complete feature with 95% coverage, security audit passed, ready to deploy
21
-
22
- ---
23
-
24
- ## Step 1: Plan the Feature (30 minutes)
25
-
26
- ### What You Do
27
-
28
- Open VS Code, start a chat with Copilot:
29
-
30
- ```
31
- @athena: Plan JWT authentication with refresh tokens
32
-
33
- Requirements:
34
- - User login with email + password
35
- - JWT access token (15 min expiry)
36
- - Refresh token (7 day expiry)
37
- - Secure token storage (httpOnly cookies)
38
- - Token verification on protected routes
39
- - Rate limiting (5 attempts/min)
40
- - OWASP Top 10 compliant
41
-
42
- Please create a detailed 3-4 phase implementation plan.
43
- ```
44
-
45
- ### What Athena Does
46
-
47
- Athena researches patterns, calls Apollo for existing auth code, and creates:
48
-
49
- ```
50
- 📋 Plan: JWT Authentication
51
- ├─ Phase 1: Database Schema (Demeter)
52
- │ ├─ Tasks: Create user + token tables
53
- │ ├─ Test requirements: 5 test cases
54
- │ └─ Risk: Zero-downtime migration
55
- ├─ Phase 2: Backend Services (Hermes)
56
- │ ├─ Tasks: JWT service + endpoints
57
- │ ├─ Test requirements: 8 test cases
58
- │ └─ Risk: Token expiry edge cases
59
- ├─ Phase 3: Frontend Integration (Aphrodite)
60
- │ ├─ Tasks: LoginForm + useAuth hook
61
- │ ├─ Test requirements: 6 test cases
62
- │ └─ Risk: Token refresh race condition
63
- └─ FAQ: Answers to common questions
64
- ```
65
-
66
- ### What You Do
67
-
68
- 1. Review the plan presented by Athena in chat
69
- 2. **Ask questions or approve**
70
- - If concerns: `@athena: Please adjust plan because...`
71
- - If approved: "Plan looks good, let's proceed"
72
-
73
- ### ⏸️ PAUSE POINT 1: Plan Approval
74
-
75
- ```
76
- Athena: ✅ Plan approved! Ready to orchestrate implementation
77
- Zeus: Starting Phase 1 - Database Schema
78
- ```
79
-
80
- ---
81
-
82
- ## Step 2: Orchestrate Implementation
83
-
84
- ### Phase 1: Database Schema
85
-
86
- **Zeus delegates to Demeter:**
87
- ```
88
- @demeter: Implement database schema for JWT auth
89
-
90
- Requirements:
91
- - User table: id, email, hashed_password
92
- - Token table: id, user_id, token, issued_at, expires_at, revoked_at
93
- - Indexes: user(email), token(user_id, token)
94
-
95
- TDD: RED → GREEN → REFACTOR
96
- Coverage target: >80%
97
- ```
98
-
99
- **Demeter does:**
100
- 1. Write FAILING migration test (RED)
101
- 2. Write minimal migration (GREEN)
102
- 3. Refactor (REFACTOR) — add types, indexes, constraints, timestamps
103
-
104
- **Demeter delivers:** Schema files + tests, >80% coverage
105
-
106
- **Themis reviews:** Coverage, security, performance, tests → APPROVED
107
-
108
- **Background dispatch for independent phases (OpenCode v1.16.2+):**
109
- If Phase 2 (backend) and Phase 3 (frontend) have no file dependencies, Zeus can dispatch both in **background** simultaneously and continue working while they execute. This eliminates the sequential wait.
110
-
111
- ### ⏸️ PAUSE POINT 2: Phase Review
112
-
113
- ```
114
- Zeus: "Phase 1 complete! Coverage: >80% ✅ Security: ✅ Tests: passing ✅
115
- Ready to continue to Phase 2?"
116
-
117
- User: "continue"
118
- ```
119
-
120
- ### Phase 2: Backend Services
121
-
122
- **Zeus delegates to Hermes:**
123
- ```
124
- @hermes: Implement backend services for JWT auth
125
-
126
- Create:
127
- 1. JWTService: generate, verify, refresh JWT
128
- 2. AuthService: handle login/logout
129
- 3. Auth endpoints: POST /auth/login, POST /auth/refresh, GET /auth/verify
130
-
131
- TDD: RED → GREEN → REFACTOR
132
- Coverage target: >80%
133
- ```
134
-
135
- **Hermes does (TDD):**
136
- 1. Write failing test for JWT generation (RED)
137
- 2. Write minimal JWT service (GREEN)
138
- 3. Refactor with proper types, error handling (REFACTOR)
139
- 4. Repeat for all endpoints
140
-
141
- **Hermes delivers:** Services + tests, >80% coverage
142
-
143
- **Themis reviews:** Coverage, security (OWASP), performance → APPROVED
144
-
145
- ### ⏸️ PAUSE POINT 2: Phase Review
146
-
147
- ```
148
- Zeus: "Phase 2 complete! Coverage: >80% ✅ Security: OWASP ✅ Tests: passing ✅
149
- Ready to continue to Phase 3?"
150
-
151
- User: "continue"
152
- ```
153
-
154
- ### Phase 3: Frontend Integration
155
-
156
- **Zeus delegates to Aphrodite:**
157
- ```
158
- @aphrodite: Implement frontend for JWT auth
159
-
160
- Create:
161
- 1. LoginForm component
162
- 2. useAuth hook for state management
163
- 3. Protected route wrapper
164
-
165
- TDD: RED → GREEN → REFACTOR
166
- Coverage target: >80%
167
- ```
168
-
169
- **Aphrodite does (TDD):**
170
- 1. Write failing component test (RED)
171
- 2. Write minimal component (GREEN)
172
- 3. Refactor with proper accessibility, error handling (REFACTOR)
173
-
174
- **Aphrodite delivers:** Components + tests, >80% coverage
175
-
176
- **Themis reviews:** Coverage, accessibility, security → APPROVED
177
-
178
- ### ⏸️ PAUSE POINT 2: Phase Review
179
-
180
- ```
181
- Zeus: "Phase 3 complete! Coverage: >80% ✅ Accessibility: ✅ Tests: passing ✅
182
- All phases approved!"
183
- ```
184
-
185
- ---
186
-
187
- ## Step 3: Final Summary
188
-
189
- ```
190
- ✅ JWT Authentication Complete
191
-
192
- 📊 Metrics:
193
- - 3 phases: Database, Backend, Frontend
194
- - >80% coverage across all layers
195
- - Security: OWASP compliant ✅
196
- - All tests passing ✅
197
-
198
- 🚀 Ready to commit
199
- ```
200
-
201
- ---
202
-
203
- ## Step 4: Git Commit
204
-
205
- ### ⏸️ PAUSE POINT 3: Git Commit
206
-
207
- ```
208
- Zeus: "All phases approved! Ready to commit."
209
-
210
- Suggested commit message:
211
- feat: Add JWT authentication with refresh tokens
212
-
213
- - Create User + Token database schema
214
- - Implement JWTService + AuthService
215
- - Add login, refresh, verify endpoints
216
- - Create LoginForm + useAuth hook
217
- - Full TDD: >80% coverage
218
- - Security: OWASP Top 10 compliant
219
-
220
- User: git add -A && git commit -m "..."
221
- ```
222
-
223
- ---
224
-
225
- ## Quick Reference: Workflow Commands
226
-
227
- ```bash
228
- # Step 1: Plan
229
- @athena: Plan [feature description]
230
-
231
- # Step 2: Orchestrate
232
- @zeus: Implement feature using plan
233
-
234
- # Step 3: At pause points
235
- # - Review phase results
236
- # - Approve before proceeding
237
-
238
- # Step 4: Commit
239
- git add -A
240
- git commit -m "feat: ..."
241
-
242
- # Step 5: Deploy
243
- git push origin [branch]
244
- ```
245
-
246
- ---
247
-
248
- ## Troubleshooting
249
-
250
- ### Problem: Phase coverage is <80%
251
- **Solution:** Implementer adds missing test cases, re-runs coverage, Themis re-reviews.
252
-
253
- ### Problem: Security audit found issue
254
- **Solution:** Relevant agent fixes (parameterized queries, input validation), re-audit, Themis approves.
255
-
256
- ### Problem: Frontend accessibility below target
257
- **Solution:** Aphrodite improves ARIA labels, keyboard navigation, re-checks, Themis approves.
258
-
259
- ---
260
-
261
- ## Common Patterns
262
-
263
- ### Pattern 1: Simple Bug Fix (Skip Athena)
264
- ```
265
- Discovery: @apollo: Find bug in authentication
266
- Fix: @hermes: Fix the validation error
267
- Review: @themis: Auto-invoked after fix
268
- Result: Minimal change, minimal risk (~30 min)
269
- ```
270
-
271
- ### Pattern 2: Complex Feature (Full System)
272
- ```
273
- Plan: @athena: Plan architecture
274
- Orchestrate: @zeus: Implement using plan
275
- Result: Complete feature, >80% coverage (1-2 days)
276
- ```
277
-
278
- ### Pattern 3: Database Optimization
279
- ```
280
- Discovery: @apollo: Find N+1 queries
281
- Optimize: @demeter: Add indexes + optimize
282
- Review: @themis: Auto-invoked
283
- Result: 10x faster queries (~2 hours)
284
- ```
285
-
286
- ---
287
-
288
- ## Pro Tips
289
-
290
- 🎯 **Plan First** — Saves 2-3x rework time
291
- 🎯 **Use Pause Points** — You control when to proceed
292
- 🎯 **Trust Themis** — Code review catches issues early
293
- 🎯 **Commit Atomically** — One phase = one commit
294
- 🎯 **Test First** — RED tests before code
295
- 🎯 **Coverage Matters** — <80% = blocked, no exceptions
296
- 🎯 **Security First** — Themis enforces OWASP compliance
297
- 🎯 **Background Dispatch** — Use OpenCode v1.16.2+ background agents to run independent phases in parallel without polling
298
-
299
- ---
300
-
301
- ## Next Steps
302
-
303
- 1. ✅ Read this guide
304
- 2. ✅ Review agent reference in `agent-coordination/SKILL.md`
305
- 3. ✅ Review TDD standards in `tdd-with-agents/SKILL.md`
306
- 4. 🚀 Start your first feature: `@athena: Plan [your idea]`
307
-
308
- ---
309
-
310
- **Philosophy:** Plan → Orchestrate → Review → Commit → Deploy
311
- Every phase has a pause point where YOU control the outcome.