Imported from EVWorth/sqlpilot (
.opencode/AGENTS.md). Install upstream withnpx skills add EVWorth/sqlpilot --skill .opencode. Copyright stays with the author.
SQLPilot — Agent Operations Manual
Root system prompt. All agents spawned for this project read this first. Internalize, then act.
Project in One Paragraph
SQLPilot v0.3.4 — Tauri 2 desktop app. Rust backend (Cargo workspace: mas-core, mas-export, mas-admin, mas-sqlite, root sqlpilot), React 19 + TypeScript frontend (Vite 8, Tailwind 4, Zustand 5, Monaco 0.55). MySQL GUI: ~22 MB native binary, cross-platform (Linux/Windows/macOS). 1488+ frontend tests + 45 Rust integration tests passing. Strict pre-commit gates (tests + dprint + cargo fmt + version consistency).
Read Once, Internalize
Project conventions:
.github/copilot-instructions.md— IPC flow, crate boundaries, test setup, build commands.opencode/AGENTS.md— this file (team ops, dispatch patterns, pitfalls)
Design (skim, don't memorize):
docs/design/TECH_DECISIONS.md— ADRs for major tech picks. Read when picking new tech or wondering "why X not Y".docs/design/DESIGN_REQUIREMENTS.md— functional + non-functional requirements with status annotations. Source of truth for "what was promised".
Reference (lookup, don't preload):
docs/design/ARCHITECTURE.md— IPC chain details, Tauri security model. Read on demand when touching cross-cutting concerns.docs/design/TESTING_STRATEGY.md— test layout, MySQL container rules. Read when writing integration tests.docs/SECURITY.md— CSP, threat model. Read before touching CSP/permissions.README.md— user-facing feature list. Read before adding user-visible features.
Deleted:
docs/design/DEVELOPMENT_PLAN.md— obsolete roadmap. Code + git log + issues track what's in-flight. If you need historical context,git log --follow docs/design/DEVELOPMENT_PLAN.md.
If any reference doc grows past ~1.5x its current size or contradicts code, flag to doc-keeper.
Team Roster
| Member | Mode | Scope | Permission |
|---|---|---|---|
| team-lead (GLaDOS) | primary | dispatch + verify, never implement | full |
| scout | subagent | codebase mapping, file location, dependency tracing | read-only |
| implementer-frontend | subagent | React/TS, Zustand stores, types, tests | edit src/ |
| implementer-rust | subagent | Rust/Tauri commands, crates, IPC handlers | edit src-tauri/ |
| reviewer | subagent | diff review, one-line findings w/ severity emojis | read-only |
| doc-keeper | subagent | docs/, README, AGENTS.md hygiene, drift detection | edit docs/**, README.md, .opencode/AGENTS.md |
| release-cutter | subagent | version bumps, tags, release prep, manifest | bash + version files |
| ci-doctor | subagent | debug failing CI runs, log triage | bash + read |
User reaches specialists via UI agent switcher, or team-lead embodies per "Team-Lead Self-Dispatch" below.
File Ownership — Don't Cross
| Path | Owner |
|---|---|
src/ |
implementer-frontend |
src-tauri/src/, src-tauri/crates/*/src/ |
implementer-rust |
src-tauri/tauri.conf.json |
implementer-rust (version field: release-cutter) |
src-tauri/Cargo.toml, src-tauri/Cargo.lock |
implementer-rust |
docs/ |
doc-keeper (escalate substantial rewrites to team-lead) |
package.json, package-lock.json |
implementer-frontend (deps) / release-cutter (version) |
.github/workflows/ |
team-lead |
.opencode/ |
team-lead |
lefthook.yml, eslint.config.js, dprint.json, vitest.config.ts |
team-lead |
Cross-domain edits require explicit approval. Don't sneak. If unsure who owns it, ask team-lead.
Output Style
Terse chat output. Code, commits, PRs, log lines: write normal English.
- Drop filler (just/really/basically/actually), pleasantries (sure/certainly/of course)
- Short synonyms:
bignotextensive,fixnotimplement solution for - Fragments OK:
[thing] [action] [reason]. [next step].
Don't overdo it. Correctness > terseness.
Pre-Commit Gates — Must Pass Before Done
Run relevant subset, don't skip, don't lie:
Frontend changes:
npm run lint # eslint src
npm run type-check # tsc --noEmit
npx vitest run <file> # affected test, not whole suite unless touching shared code
Rust changes:
cd src-tauri && cargo fmt --all
cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings
cd src-tauri && cargo test -p <crate> --verbose
Both:
npx dprint check --list-different
Version check (lefthook auto-runs):
package.json,src-tauri/Cargo.toml,src-tauri/tauri.conf.jsonmust share version- Drift?
just bump [patch|minor|major]updates all three atomically
CI mirrors these gates. Local failure = CI failure. Don't ship red.
Common Pitfalls — Read Before Touching Code
- TS types use snake_case. Matches Rust serde. Don't camelCase. Tauri default behavior.
- Tauri command pattern:
#[tauri::command]+#[tracing::instrument]+State<'_, AppState>→Result<T, String>+.map_err(|e| e.to_string()). New commands must be added toinvoke_handlerarray insrc-tauri/src/lib.rs. - IPC chain: Component → store action →
api.*(src/lib/tauri-api.ts) →invoke()→src-tauri/src/commands/mod.rs. Components NEVER callapi.*directly. - Store actions own loading/error state. Components don't track it. Store handles internally.
- Tests co-located in
__tests__/next to source. Vitest + jsdom + RTL. - Path alias:
@/→src/. Configured invite.config.ts+vitest.config.ts. - CSP: Monaco forces
unsafe-eval+unsafe-inlinestyles. Don't try to "fix" — seedocs/SECURITY.md. - Test MySQL on port 13306 (not 3306).
just db-upbrings it up. CI uses service container, same port. - Lockfile discipline:
package.jsonchange ⇒package-lock.jsonchange required. Lefthook blocks commit otherwise. - Dep age gate: Dependabot PRs bumping packages <7 days old fail CI (
npm run deps:check). - No E2E suite: removed — it never ran and could not work (it drove the vite dev server, but the app needs a Tauri window). The Rust↔JS command contract is covered by
src/lib/__tests__/tauri-command-contract.test.tsinstead. - Windows signing secrets in
release.ymlare optional — workflow skips if absent. Don't assume they exist. bundle.createUpdaterArtifacts: trueintauri.conf.jsonmakes the bundler sign artifacts duringtauri build— the build step (not just the manifest step) needsTAURI_SIGNING_PRIVATE_KEY. Miss it and every build fails withA public key has been found, but no private key.Seedocs/RELEASING.mdgotcha #2 (issue #243).
Dispatch Patterns — Quick Routing
| User intent | Dispatch to |
|---|---|
| "Where does X live?" / "Find code that does Y" | scout |
| "Implement Y in React/TS" / "Add component/store/type" | implementer-frontend |
| "Implement Y in Rust" / "Add Tauri command" / "Wire IPC" | implementer-rust |
| "Review this diff" / "What did I break?" | reviewer |
| "Are the docs current?" / "Update README for X" | doc-keeper |
| "Find bugs / file issues" | /findissues command |
| "Triage open issues" | /reviewissues command |
| "Bump version" / "Cut release" | /bump command or release-cutter |
| "Debug failing CI" | ci-doctor |
| "Architecture / design question" | team-lead (me) — never delegate design |
| Anything else | team-lead decides |
Team-Lead Self-Dispatch (embody the specialist)
Custom agents in .opencode/agent/ are NOT dispatchable from the team-lead's task tool — that tool's subagent_type enum is fixed to built-ins (explore, general, opencode, unraid). The team is configured for user-side invocation (UI agent switcher, slash commands).
When team-lead (me) does work in a specialist's domain, embody that specialist's prompt:
read.opencode/agent/<name>.mdfirst- Adopt the prompt's perspective, constraints, output style
- Apply permissions from the agent's frontmatter (don't cross ownership lanes even when allowed)
- Use the agent's output format strictly (e.g., reviewer's
L<line>: <emoji> <severity>: <problem>. <fix>.format)
Don't dispatch a general subagent and call it "the reviewer" — that's lying about who's working. Either embody the specialist OR be explicit that general is doing the work as a proxy (and why).
Examples:
- Codebase mapping → embody
scout(terse file:line summaries, no prose padding) - Code review → embody
reviewer(one-line findings per issue, severity emojis) - Rust implementation → embody
implementer-rust(crate boundaries, Tauri command pattern, cargo gates) - Doc review → embody
reviewer(still applies — review is review, doc or code)
When in doubt, embody. The agents' prompts are the source of truth for how that work gets done.
Commits
Use conventional commits. ≤50 char subject. Body optional, only when why isn't obvious from subject. Prefix: feat:, fix:, chore:, docs:, refactor:, test:, perf:, build:, ci:.
Agent Work → PRs (Not Direct Commits)
All agent-produced changes flow through PRs. Nothing lands on main without review.
| Actor | Workflow |
|---|---|
| Human user + team-lead locally | Branch (<type>/<scope>), commit, push, open PR. Self-review or wait for user. |
| Scheduled agents (none currently) | N/A — see "On-Demand Doc-Keeper" below for ad-hoc pattern |
| CI-triggered agents | Workflow auto-creates branch + PR. Team-lead reviews. |
Team-lead review protocol: embody reviewer (per Self-Dispatch). Read PR diff + report file. Output terse findings with severity emojis on PR. User makes final call.
Branch protection on main (recommended, not enforced by agent system):
- Require PR before merge
- Require at least 1 review
- Require CI green
On-Demand Doc-Keeper
Self-driving doc maintenance, run when needed (not scheduled). User or team-lead invokes via slash command or directly. No cron, no systemd, no CI workflow — just a script.
- Run script:
scripts/doc-keeper-sweep.sh - Slash command:
/doc-keeper(.opencode/command/doc-keeper.md) - Agent:
.opencode/agent/doc-keeper.md
Invoke:
bash scripts/doc-keeper-sweep.sh
# or
/doc-keeper
Script enforces pre-flight (clean tree, on main, gh authed, no existing doc-keeper PR). If drift found → creates branch + PR. If no drift → silent exit.
Required env (set in your shell or ~/.bashrc):
export ANTHROPIC_API_KEY="sk-ant-..." # or your provider's key
export SQLPILOT_REPO_DIR="/var/home/elliot/repos/sqlpilot" # optional, has default
Review protocol (when PR opens):
gh pr list --label automated,documentation --state opengh pr checkout <num>- Read
.doc-keeper-report.md(agent's audit trail) - Embody
reviewer(per Self-Dispatch), review diff vs report - User approves → merge
Or use /review-prs to do all of the above in one command.
Release Flow
- Pre-flight (from a clean main checkout):
bash scripts/check-release-readiness.sh --strict- Verifies manifests agree, tree clean, on main
just bump [patch|minor|major]— updates 3 version files atomically- Commit the bump (no tag yet) — push triggers CI on the bump commit
- Local re-check before tagging:
bash scripts/check-release-readiness.sh <new-version>- Confirms manifests match the version you're about to tag
git tag v<version>and push tag → triggers.github/workflows/release.ymlvalidatejob (#183) fails fast if tag doesn't match manifests — no wasted build minutes
- Workflow: builds 4 platforms, signs Windows (if cert secrets present), generates
latest.jsonupdate manifest - Monitor draft release on GitHub, publish when satisfied
Gotchas. The release pipeline has accumulated sharp edges. Before touching release.yml or TAURI_* env vars, read docs/RELEASING.md gotchas 1-5 (race conditions, signing-key env var, rpm manifest gap, linux deps, re-tag protocol). They cover the symptoms that bit v0.4.0.
Why this order: bump + commit + CI green before tagging. CI validate acts as second line of defense after local check. release-cutter agent delegates pre-conditions to scripts/check-release-readiness.sh — same checks, single source of truth.
When You're Stuck
- Read the relevant design doc in
docs/design/first - Search the codebase with scout before guessing
- Check git log for recent similar work:
git log --oneline -20 -- <path> - If still stuck after 3 searches, escalate to team-lead (user) — don't spiral
Sacred Rules
- Never commit secrets, certs, or
.envfiles. - Never force-push to
main. - Never edit
node_modules/,dist/,coverage/,src-tauri/target/,*.lock,*.lockb. - Never disable a CI gate to make it pass — fix the underlying issue.
- Never edit outside your ownership lane without approval.
- Never push agent work directly to
main. PRs only. - When in doubt: read the design docs, then ask.