- OS: Linux / Shell: bash
- Web Server: nginx / Database: MariaDB
- Backend: PHP 8.5+ (flat procedural / class-based, no MVC, no router)
- Frontend: HTML5, CSS3, JS ES6+, jQuery only when vanilla JS is insufficient
- CSS: SCSS → Dart Sass → minified / JS: uglify-js → minified
- Tests: Pest PHP v4 on PHPUnit 12
- Version Control: Git + Conventional Commits + signed commits
- OS: Linux
- Server provisioned via https://github.com/kyaulabs/aarch/blob/master/pkg/nginx.pkg
- Web root:
/nginx/https/<domain>/www(symlinked from/nginx/git/<app>/) - Logs:
/nginx/logs/<domain>/(one directory per domain, dots in domain → underscores)- PHP:
php.log - nginx access:
access-<app>_<domain>.log - nginx error:
error-<app>_<domain>.log - Rotated:
.N.zstdsuffix (e.g.php.log.1.zstd)
- PHP:
- Temp directory:
/tmp
PHP pages include Aurora, output HTML directly, and interact with the DB via raw SQL or Aurora's SQL handler. No controllers, no templating engine, no router. backend/ holds PHP logic not web-accessible.
CONTEXT.md(root) — domain glossary, entities, invariants, boundaries, non-goals. Read before domain-coupled work (seedomain-contextskill). Draft or refresh it via/prime.adr/— Architecture Decision Records (Nygard format). Write one for hard-to-reverse or cross-cutting decisions (seeadrskill).
├── AGENTS.md ← Stack, boundaries, pointers (loaded every session)
├── CONTEXT.md ← Domain glossary, entities, invariants, non-goals
├── opencode.json ← Wires instructions + agent definitions + permissions
├── adr/ ← Architecture Decision Records (Nygard format)
├── aurora/ ← Aurora PHP Framework (git submodule)
├── backend/ ← Backend PHP logic (not web-accessible)
│ └── migrations/ ← Forward-only SQL migrations (timestamp-prefixed)
├── cdn/
│ ├── css/ ← GENERATED — do not edit
│ ├── javascript/ ← GENERATED — do not edit
│ ├── sass/ ← SCSS source (edit these)
│ └── js/ ← JS source (edit these)
├── tests/
│ ├── Unit/
│ ├── Feature/
│ ├── Integration/
│ └── Browser/
├── <app>/ ← Public webroot (<app>.<domain>)
├── <app>.sql
└── <app>.nginx.conf
Projects live in /nginx/git/<app>, symlinked into /nginx/https/<domain>.
Important
- NEVER edit
cdn/css/*.min.cssorcdn/javascript/*.min.js— these are generated (edit source incdn/sass/andcdn/js/; seeconventions.mdfor details) - NEVER commit
.envfiles — use.env.exampleonly - Do not access external APIs without explicit permission
- Do not modify files outside the project directory
- New dependencies must be explicitly noted
- When glob/grep returns unexpected empty results, verify with
lsbefore concluding a file does not exist
See .opencode/docs/conventions.md for file naming conventions.
Important
- Every file starts with an RCS-style header — see
rcs-headerskill - Every file ends with a vim modeline — see
rcs-headerskill - PHP classes/methods: PHPDoc (PSR-5) with params, return types, exceptions
- No explanatory comments unless explicitly requested
Covered in conventions.md.
Important
All new code follows Red → Green → Refactor. No exceptions.
Use the @tdd agent for any new feature or bug fix.
Minimum 80% line coverage. Run: php -d pcov.enabled=1 vendor/bin/pest --coverage
Use the @test-audit agent to review an existing test suite.
Pre-push gate: /check (php-cs-fixer + stylelint + eslint + pest --coverage).
The full methodology, end to end. Follow this sequence for changes with a behavior delta. Purely trivial changes with no behavior delta (typos, docs, RCS headers, style-only, patch deps, test-only fixes) follow a fast-path — see the brainstorming skill for the full definition.
brainstorming → prototype (if needed) → writing-plans → executing-plans → @tdd (per task) → verification-before-completion → /check → @code-review
- Brainstorm the change (grilling skill) → spec in
docs/specs/. - Prototype (if technical viability is uncertain) → throwaway code to answer the question, then delete (prototype skill).
- Plan the implementation (writing-plans skill) → plan in
docs/plans/. - Execute the plan (executing-plans skill) → dispatch tasks to
@tdd, review between tasks. - Implement each task via
@tdd(Red → Green → Refactor, vertical slices). - Verify completion (verification-before-completion skill).
- Gate with
/check(lint + coverage 80%). - Review with
@code-reviewbefore push.
For non-trivial or cross-cutting changes, insert @architect before step 4.
For bugs, use @debug (disciplined 6-phase loop) before @tdd on the fix.
For architectural entropy, run /improve-architecture on a cadence.
Linting is enforced by .github/hooks/pre-commit — it blocks commits on failure.
Commit message format is enforced by .github/hooks/commit-msg via commitlint.
To activate hooks after cloning: bash .github/scripts/install-hooks.sh
For linting details and responsive/mobile-first CSS rules, see scss-mobile-first skill.
- Branches:
main(production),develop(integration) - Features:
feat/<username>-<hash>-<description> - Commits: Conventional Commits format (type[scope]: subject) — see
conventional-commitsskill - Signed commits required
- Every commit must include
Plan-by:(sourced fromagent.plan.modelinopencode.json),Acked-by:(sourced fromagent.build.modelinopencode.json— model ID segment after the last/), andSigned-off-by:(user) footers. Default Signed-off-by:kyau <git@kyaulabs.com>. - No squash merges. Each logical change is its own atomic commit — the git history serves as the development and evaluation log. A pre-push hook warns on single-commit branches that look like squashes.
After implementing any change — whether via @tdd, a direct fix, an issue
tracker resolution, or a fast-path trivial change — produce a commit message
in conventional commits format before committing. Load the
conventional-commits skill and produce: type[scope]: subject + Plan-by +
Acked-by + Signed-off-by footers. The commit-msg hook blocks invalid messages,
but the
message should be well-formed before you reach the hook.
@tddand@resolve-merge-conflictsare permitted togit addandgit commit— commits happen inside disciplined cycles where the commit message is presented to the user before execution.- The
buildprimary agent prompts (ask) beforegit addorgit commit— the user sees the full command including the commit message in the approval dialog. Used by/release,/build-assets, and design-document commits frombrainstorming. git pushis denied to every agent. Only the human pushes.
SCSS: sass --style=compressed cdn/sass/source.scss cdn/css/output.min.css
JS: uglifyjs cdn/js/source.js -o cdn/javascript/output.min.js -c -m
Assets are built manually. No watchers.
Important
composer.lock and package-lock.json are committed to the repository.
This ensures deterministic, auditable dependency trees and allows
audit-deps to scan known vulnerabilities on a fresh clone without
installing unvetted packages first.
After any dependency change (adding, removing, or updating a package), regenerate and commit the updated lockfiles:
composer update # regenerates composer.lock
npm install # regenerates package-lock.json
git add composer.lock package-lock.jsonSubmodule at aurora/. Entry: require_once(__DIR__ . "/../aurora/aurora.inc.php")
For the standard page template, see the aurora-page skill.
Load these on demand when the task requires them:
| Skill | When to use |
|---|---|
brainstorming |
Before any creative work — features, components, behavior changes. Grilling → design → spec |
prototype |
Answering a technical viability question with throwaway code before committing to a plan |
writing-plans |
After brainstorming approval — produces a bite-sized TDD implementation plan |
executing-plans |
After writing-plans — dispatches tasks to @tdd with two-mode execution (inline or dispatch), per-task review gates, and halt/re-plan policy |
finding-duplicate-functions |
Scanning for semantic duplication — two-phase (classical extraction + LLM intent-clustering), complements /improve-architecture's deletion test |
finishing-a-development-branch |
When a feature branch is complete — verify readiness (checklist), present disposal options (merge/PR/keep/discard), enforce no-squash policy |
verification-before-completion |
Before declaring a task done — verifies tests pass, no debug artifacts, lint clean |
rcs-header |
Creating or modifying any source file |
receiving-code-review |
Triaging and responding to @code-review findings — severity triage matrix, anti-over-compliance rules, deferral discipline |
aurora-page |
Creating a new PHP page |
scss-mobile-first |
Writing or reviewing SCSS (breakpoints, units, build) |
frontend-design |
Writing or reviewing visual language — responsive/mobile-first, CSS transitions, CSS-driven flow, neumorphism, default theme + tokens |
frontend-architecture |
Structuring frontend JS — progressive enhancement, module pattern, jQuery policy, token consumption, CSP rules |
accessibility |
Writing or reviewing markup/SCSS/JS for UI — WCAG 2.2 AA, focus, motion, neumorphism contrast floor |
security-coding |
Defensive coding in the no-framework stack — SQL/XSS/CSRF, sessions, passwords, headers |
database |
Schema design, <app>.sql, migrations, indexing, SQL style |
domain-context |
Before domain-coupled work — read/update CONTEXT.md |
adr |
Writing, reviewing, or superseding an Architecture Decision Record |
systems-design |
Designing a non-trivial change — ADR vs RFC, C4-lite, interface design |
conventional-commits |
Writing or reviewing commit messages |
opencode-docs |
Vendored opencode.ai/docs reference — config schemas, plugin hooks, permission rules, SDK API. Load instead of guessing or calling /research |
pest-browser |
Writing browser tests |
audit-deps |
Scanning PHP/JS dependencies for known CVEs |
writing-skills |
Authoring new skills, agents, commands, or docs in .opencode/ |
| Agent | Mode | When to use |
|---|---|---|
@tdd |
subagent | Any new feature or bug fix requiring tests |
@test-audit |
subagent | Auditing an existing test suite for quality |
@code-review |
subagent | Reviewing staged changes before push |
@architect |
subagent | Read-only evaluation of a proposed change against CONTEXT.md + ADRs before implementation |
@resolve-merge-conflicts |
subagent | Resolving in-progress git merge/rebase conflicts |
@semgrep |
subagent | SAST scanning — diff audit + full scan (PHP/JS/secrets) |
@debug |
subagent | Investigating bugs — disciplined 6-phase loop: feedback loop → reproduce → hypothesise → instrument → fix → post-mortem. Build-mode agent with scoped investigation write (repro tests, harnesses, instrumentation); not invocable from Plan mode. |
@docs-writer |
subagent | Generating PHPDoc, RCS headers, and documentation |
| Command | Purpose |
|---|---|
/prime |
Draft or regenerate CONTEXT.md from the codebase |
/check |
Pre-push gate: php-cs-fixer + stylelint + eslint + pest --coverage (80%) |
/release |
git-cliff changelog + signed tag + gh release command |
/deploy |
Post-pull production deploy — asset rebuild, opcache clear, log tail |
/research |
Cited research via @scout + web (see .opencode/docs/research.md) |
/build-assets |
Rebuild minified CSS and JS from source |
/security |
SAST scan + dependency CVE audit in one pass |
/improve-architecture |
Scan codebase for deepening opportunities → Obsidian markdown report |
/handoff |
Compact current conversation into a handoff document for another session |
/setup |
Interactive project configurator — replaces <app>/<domain>/[EMAIL] placeholders across the harness, sets accent theme |
/plan-to-issues |
Parse a plan from docs/plans/ and create a GitHub epic + task issues via gh |
/teach |
Explain recently completed work at the user's level — what changed, why this approach, what trade-offs were considered |