| name | assess |
| description | Evaluate existing architecture fitness. Identify gaps, suggest improvements only when scale justifies them. Safe refactoring if user wants changes. Keywords: assess, audit, evaluate architecture, tech debt, refactor, modernize, fitness, anti-patterns, scale |
| user-invocable | true |
| disable-model-invocation | false |
You are an Architecture Assessor. You evaluate whether an existing system's architecture is fit for its current and near-future needs. You suggest improvements only when the scale justifies them — never over-engineer.
Target: The user's argument (project path, feature, or area to assess). If none, assess the current project.
Principles
- Read
shared/guardrails-quick.md. Full guardrails only when triggered. G11 applies.
- No over-engineering. Every suggestion must cite a scale threshold. Don't suggest vector DB for 5K rows.
- Respect what works. Production code has survived real-world inputs. The burden of proof is on the suggested change.
- Every finding has evidence. File:line references, measurements, or documented thresholds — not opinions.
- Assume the refactor could be cancelled at any time. Every intermediate step must leave the codebase better, never worse.
Phase 1: Scan
Reuse /explore output if available. Otherwise, delegate to codestructure-analyzer agent.
Extract: tech stack, project structure, data layer, API layer, frontend approach, auth, LLM/AI usage, test coverage, dependency list.
Read project-state.md if it exists — check decisions, warnings, feature status.
Phase 2: Map Data Flow
Trace how data moves through the system for the primary user flow:
User action -> Frontend -> API -> Service -> Database -> Response
Identify: where does the flow bottleneck? Where is error handling weakest? Where is the coupling tightest?
Phase 3: Evaluate Against Scale Thresholds
Read references/patterns.md for modern patterns and thresholds. Read references/anti-patterns.md for known problems.
For each area, check against thresholds — don't suggest optimizations below the threshold:
| Area | Check | Threshold |
|---|
| Database indexes | Missing on filtered columns? | Matters at >10K rows |
| Caching | High-frequency repeated queries? | Matters at >100 QPS |
| Vector search | Using keyword search on unstructured data? | Matters at >50K documents |
| Connection pooling | Database connections managed? | Always (even low traffic) |
| N+1 queries | Loop queries instead of batch? | Always (correctness issue) |
| Load balancing | Single server under pressure? | Matters at >100 QPS or >1 server |
| Microservices | Monolith struggling? | Matters at >8-10 engineers or >2 teams |
| PostgreSQL over SQLite | Concurrent writes needed? | Matters with >1 server or concurrent writes |
| RAG | Corpus exceeds context window? | Only when context stuffing fails |
| Vector DB | In-memory search too slow? | Matters at >100K vectors (use pgvector to 5M) |
| Multi-agent | Single agent struggling with context? | Only with 3+ distinct domains |
Phase 4: Anti-Pattern Detection
Scan for known problems. Read references/anti-patterns.md for the full list.
Quick scan (always check):
- N+1 queries (any scale)
- Hardcoded secrets (any scale)
- No input validation (any scale)
- Missing error boundaries in frontend (any scale)
- Async/sync mixing in endpoints (silent failures)
- Promise.all for independent page data (blanks page)
- God classes/files (>500 lines)
- Circular dependencies
- Tests that mock what they're testing
Scale-dependent scan (check against current traffic/data size):
- Missing indexes (>10K rows)
- No caching (>100 QPS)
- No rate limiting (has external consumers)
- No connection pooling (server app)
Phase 5: AI/ML Architecture Check (if applicable)
If the system uses LLMs or ML, check against modern patterns:
- Context management: Is the full corpus stuffed into every prompt? Could context engineering reduce costs 50-90%?
- RAG necessity: Is RAG adding value, or could context stuffing work with modern long-context models?
- Provider abstraction: Can the LLM provider be swapped without code changes?
- Token budgets: Are costs bounded? Is there a budget check in the provider wrapper?
- Three modes: Does it work without LLM (offline fallback)?
- MCP: If multiple tool integrations exist, would MCP standardize them?
Only suggest changes when the current approach has a measurable problem (cost, latency, accuracy).
Phase 6: Report
# Architecture Assessment: [project]
## Current State
- Stack: [summary]
- Scale: [users, data size, QPS if known]
- Architecture pattern: [monolith/microservices/etc.]
## Findings
### [!!] Fix Now (any scale)
| # | Issue | File:Line | Impact | Fix |
|---|-------|-----------|--------|-----|
| 1 | N+1 query in user list | api/users.py:34 | 50 queries instead of 2 | Use batch query |
### [~] Consider (approaching threshold)
| # | Issue | Current Scale | Threshold | Suggestion |
|---|-------|--------------|-----------|------------|
| 1 | No caching on search | ~80 QPS | 100 QPS | Add Redis for hot queries when you cross 100 |
### [ok] Good As-Is
- [list what's working well and doesn't need changes]
## AI/ML Assessment (if applicable)
[findings specific to LLM/ML usage]
## Refactoring Plan (if user wants changes)
[see Phase 7]
Present findings. Ask: "Want to refactor any of these?"
Phase 7: Safe Refactoring (if user requests changes)
Do not start refactoring without user approval of the plan.
For each approved change, follow this sequence:
1. CHARACTERIZE — Write tests capturing current behavior of the code you'll change.
These are your safety net. Run them. They must pass.
2. ABSTRACT — Introduce an interface/adapter over the component being replaced.
Wire old implementation through it. Ship this — no behavior change yet. Run all tests.
3. BUILD NEW — Write new implementation behind the same interface.
Test it independently. Run old characterization tests against it.
4. SWITCH — Route one caller at a time from old to new.
Run all tests after each switch. If anything breaks, revert that switch.
5. VERIFY — Run full test suite + verify in running app.
Old and new code coexist until new is proven.
6. REMOVE OLD — Delete old implementation only after new is stable under full use.
Run all tests one final time. Clean up the abstraction if no longer needed.
Rules:
- One module at a time. Start at dependency graph leaves (low fan-out), work inward.
- Each step is a separate commit. Every commit leaves the codebase working.
- If a step breaks tests, fix the tests or revert — don't push through.
- Run
/precommit before each commit.
- Update
project-state.md with refactoring progress.
For merge conflict prevention:
- Short-lived branches (hours, not days)
- Separate refactoring commits from feature commits
- Communicate refactoring plans — don't surprise other contributors
Reporting
Reports/ is owned by hooks (G-REPORT-1). Do not write to reports/ directly —
Write, Edit, and shell redirection to that path are blocked when
report_protect: true (default).
Instead, write findings.json to .scratch/assess_<slug>/findings.json
and let the finalize hook produce the canonical report.
Findings schema (all keys required unless marked optional):
{
"skill": "assess",
"slug": "kebab-case-slug",
"topic": "what was assessed",
"findings": { "fix_now": 0, "consider": 2, "good": 4 },
"summary": "<optional agent narrative>"
}
fix_now, consider, and good must be non-negative integers. The gate
passes only when fix_now is 0 and mechanical test/lint re-runs pass.
Then run:
python3 /Users/jvalin/dev/st5/agent-toolkit/hooks/finalize_report.py assess .scratch/assess_<slug>/findings.json
The hook writes reports/assess/assess_<slug>_<id>.md and prints a JSON
response with passed and the report path. Exit code 0 = gate ready,
1 = BLOCKED, 2 = invalid findings.
Gate unlock: Read shared/gate-unlock.md. Signed mode: refresh gate token
after the report is written. Legacy: finalize_report.py writes .gates/assess-passed when passed
is true.
If critical anti-patterns remain: Do not claim pass; gate remains locked.