
Scope Appropriate Architecture
- 136 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/orchestkit
Pick a right-sized architecture for the validated product scope, team size, and timeline before committing to frameworks, services, or agent orchestration depth.
About
Scope-appropriate-architecture from Orchestkit helps teams and coding agents choose minimal viable system shapes matched to validated scope, not aspirational diagrams. It compares monolith, modular, and service options, documents tradeoffs, and blocks premature complexity in SaaS, API, and agent builds.
- scope-to-structure mapping
- YAGNI tradeoff framing
- evolutionary design
- anti-overengineering checks
- team-capacity fit
Scope Appropriate Architecture by the numbers
- 136 all-time installs (skills.sh)
- Ranked #1,227 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yonatangross/orchestkit --skill scope-appropriate-architectureAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 136 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/orchestkit ↗ |
What it does
Pick a right-sized architecture for the validated product scope, team size, and timeline before committing to frameworks, services, or agent orchestration depth.
Files
Scope-Appropriate Architecture
Right-size every architectural decision to the project's actual needs. Not every project needs hexagonal architecture, CQRS, or microservices.
Core principle: Detect the project tier first, then constrain all downstream pattern choices to that tier's complexity ceiling.
---
The 6 Project Tiers
| Tier | LOC Ratio | Architecture | DB | Auth | Tests |
|---|---|---|---|---|---|
| 1. Interview/Take-home | 1.0-1.3x | Flat files, no layers | SQLite / JSON | None or basic | 8-15 focused |
| 2. Hackathon/Prototype | 0.8-1.0x | Single file if possible | SQLite / in-memory | None | Zero |
| 3. Startup/MVP | 1.0-1.5x | MVC monolith | Managed Postgres | Clerk/Supabase Auth | Happy path + critical |
| 4. Growth-stage | 1.5-2.0x | Modular monolith | Postgres + Redis | Auth service | Unit + integration |
| 5. Enterprise | 2.0-3.0x | Hexagonal/DDD | Postgres + queues | OAuth2/SAML | Full pyramid |
| 6. Open Source | 1.2-1.8x | Minimal API surface | Configurable | Optional | Exhaustive public API |
LOC Ratio = total lines / core business logic lines. Higher ratio = more infrastructure code relative to business value.
---
Auto-Detection Signals
| Signal | Tier Indicator |
|---|---|
| README contains "take-home", "assignment", "interview" | Tier 1 |
| Time limit mentioned (e.g., "4 hours", "weekend") | Tier 1-2 |
| < 10 files, no CI, no Docker | Tier 1-2 |
.github/workflows/ present | Tier 3+ |
package.json with 20+ dependencies | Tier 3+ |
| Kubernetes/Terraform files present | Tier 4-5 |
CONTRIBUTING.md, CODE_OF_CONDUCT.md | Tier 6 |
Monorepo with packages/ or apps/ | Tier 4-5 |
When confidence is low: Ask the user with AskUserQuestion.
---
Pattern Appropriateness Matrix
| Pattern | Interview | Hackathon | MVP | Growth | Enterprise |
|---|---|---|---|---|---|
| Repository pattern | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE | REQUIRED |
| Event-driven arch | OVERKILL | OVERKILL | OVERKILL | SELECTIVE | APPROPRIATE |
| DI containers | OVERKILL | OVERKILL | LIGHT ONLY | APPROPRIATE | REQUIRED |
| Separate DTO layers | OVERKILL | OVERKILL | 1 EXTRA | 2 LAYERS | ALL LAYERS |
| Microservices | NEVER | NEVER | NEVER | EXTRACT ONLY | APPROPRIATE |
| CQRS | OVERKILL | OVERKILL | OVERKILL | OVERKILL | WHEN JUSTIFIED |
| Hexagonal architecture | OVERKILL | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE |
| DDD (bounded contexts) | OVERKILL | OVERKILL | OVERKILL | SELECTIVE | APPROPRIATE |
| Message queues | OVERKILL | OVERKILL | BORDERLINE | APPROPRIATE | REQUIRED |
| API versioning | SKIP | SKIP | URL prefix | Header-based | Full strategy |
| Error handling | try/catch | console.log | Error boundary | Error service | RFC 9457 |
| Logging | console.log | none | Structured JSON | Centralized | OpenTelemetry |
Rule of thumb: If a pattern shows OVERKILL for the detected tier, do NOT use it. Suggest the simpler alternative instead.
---
Technology Quick-Reference by Tier
| Choice | Interview | Hackathon | MVP | Growth | Enterprise |
|---|---|---|---|---|---|
| Database | SQLite / JSON file | In-memory / SQLite | Managed Postgres | Postgres + Redis | Postgres + queues + cache |
| Auth | Hardcoded / none | None | Clerk / Supabase Auth | Auth service | OAuth2 / SAML / SSO |
| State mgmt | useState | useState | Zustand / Context | Zustand + React Query | Redux / custom + cache |
| CSS | Inline / Tailwind | Tailwind | Tailwind | Tailwind + design tokens | Design system |
| API | Express routes | Single file handler | Next.js API routes | FastAPI / Express | Gateway + services |
| Deployment | localhost | Vercel / Railway | Vercel / Railway | Docker + managed | K8s / ECS |
| CI/CD | None | None | GitHub Actions basic | Multi-stage pipeline | Full pipeline + gates |
| Monitoring | None | None | Error tracking only | APM + logs | Full observability stack |
---
Build vs Buy Decision Tree (Tiers 1-3)
For Interview, Hackathon, and MVP tiers, always prefer buying over building:
| Capability | BUY (use SaaS) | BUILD (only if) |
|---|---|---|
| Auth | Clerk, Supabase Auth, Auth0 | Core product IS auth |
| Payments | Stripe | Core product IS payments |
| Resend, SendGrid | Core product IS email | |
| File storage | S3, Cloudflare R2 | Compliance requires on-prem |
| Search | Algolia, Typesense Cloud | > 10M docs or custom ranking |
| Analytics | PostHog, Mixpanel | Unique data requirements |
Time savings: Auth alone is 2-4 weeks build vs 2 hours integrate.
---
Upgrade Path
When a project grows beyond its current tier, upgrade incrementally:
Tier 2 (Prototype) → Tier 3 (MVP)
Add: Postgres, basic auth, error boundaries, CI
Tier 3 (MVP) → Tier 4 (Growth)
Add: Redis cache, background jobs, monitoring, module boundaries
Tier 4 (Growth) → Tier 5 (Enterprise)
Add: DI, bounded contexts, message queues, full observability
Extract: First microservice (only the proven bottleneck)Key insight: You can always add complexity later. You cannot easily remove it.
---
When This Skill Activates
This skill is loaded by:
brainstormPhase 0 (context discovery)implementStep 0 (context discovery)quality-gatesYAGNI check- Any skill that needs to right-size a recommendation
The detected tier is passed as context to constrain downstream decisions.
---
Related Skills
ork:brainstorm- Uses tier detection in Phase 0 to constrain ideasork:implement- Uses tier detection in Step 0 to constrain architectureork:quality-gates- YAGNI gate references this skill's tier matrixork:architecture-patterns- Architecture validation (constrained by tier)
---
References
Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"):
| File | Content |
|---|---|
interview-takehome.md | Tiers 1-2 in detail |
startup-mvp.md | Tier 3 patterns and decisions |
enterprise.md | Tiers 4-5 patterns and justification criteria |
open-source.md | Tier 6 unique considerations |
Enterprise Guide (Tiers 4-5)
Guidance for growth-stage and enterprise production applications.
Tier 4: Growth-Stage
When You're Here
- 4-15 developers on the codebase
- $10K-$500K MRR
- 10K-1M monthly active users
- SLAs exist (99.5%+ uptime)
- Compliance requirements emerging
Architecture: Modular Monolith
src/
├── modules/
│ ├── users/
│ │ ├── api/ # Module-scoped routes
│ │ ├── services/ # Business logic
│ │ ├── repository/ # Data access (NOW justified)
│ │ └── types/ # Module types
│ ├── orders/
│ │ ├── api/
│ │ ├── services/
│ │ ├── repository/
│ │ └── types/
│ └── shared/ # Cross-module utilities
├── infrastructure/
│ ├── database/ # Connection, migrations
│ ├── cache/ # Redis client
│ ├── queue/ # Background job client
│ └── monitoring/ # APM setup
└── config/ # Environment-specific configPatterns NOW Justified
| Pattern | Why Now |
|---|---|
| Repository pattern | Multiple data sources, testability matters |
| DI (light) | Constructor injection for services, no container yet |
| Module boundaries | Team ownership, independent deployment later |
| Background jobs | Email, reports, data sync — can't block requests |
| Redis cache | Database bottlenecks are real and measured |
| Structured logging | Debugging across modules needs correlation |
Patterns Still OVERKILL
| Pattern | Why Not Yet |
|---|---|
| Microservices | Monolith handles the traffic, operational overhead isn't justified |
| CQRS | Read/write patterns aren't divergent enough |
| Event sourcing | Audit log column is sufficient |
| API gateway | One service, one entry point |
| Service mesh | One service, no mesh needed |
| Custom DI container | Constructor injection is sufficient |
Database at Growth Stage
- Primary: Postgres with connection pooling (PgBouncer or managed)
- Cache: Redis for sessions, hot data, rate limiting
- Background: Redis-backed queue (BullMQ, Celery)
- Search: Postgres full-text or Typesense (if > 100K searchable records)
Testing Strategy
| Type | Coverage Target |
|---|---|
| Unit | Core business logic: 80%+ |
| Integration | All API endpoints, all service methods |
| E2E | Critical user journeys (5-10 flows) |
| Performance | Load test key endpoints (k6 or Artillery) |
| Security | OWASP top 10 scan in CI |
---
Tier 5: Enterprise
When You're Here
- 15+ developers, multiple teams
- $500K+ MRR or enterprise contracts
- 1M+ monthly active users
- Strict SLAs (99.9%+ uptime)
- Compliance: SOC2, HIPAA, GDPR, or similar
- Incidents cost real money
Architecture: Domain-Driven (Hexagonal)
src/
├── domains/
│ ├── identity/ # Bounded context
│ │ ├── application/ # Use cases, commands, queries
│ │ ├── domain/ # Entities, value objects, events
│ │ ├── infrastructure/ # Repos, adapters, external services
│ │ └── presentation/ # Controllers, DTOs, serializers
│ ├── billing/
│ │ └── ...
│ └── catalog/
│ └── ...
├── shared/
│ ├── kernel/ # Shared value objects, base classes
│ └── infrastructure/ # Cross-cutting: auth, logging, tracing
├── api-gateway/ # Route to domains
└── workers/ # Background processors per domainPatterns NOW Justified
| Pattern | Justification |
|---|---|
| Hexagonal / Clean Architecture | Team boundaries align with domain boundaries |
| DDD (bounded contexts) | Complex domain logic requires explicit modeling |
| CQRS | Read and write patterns have diverged significantly |
| Event-driven | Cross-domain communication needs decoupling |
| API gateway | Multiple services, unified entry point |
| Full DI container | Complex dependency graphs across domains |
| RFC 9457 errors | External API consumers need structured errors |
| OpenTelemetry | Distributed tracing across services |
Justification Required
Even at enterprise scale, these patterns need specific justification:
| Pattern | Only When |
|---|---|
| Microservices extraction | Team can't deploy independently, proven bottleneck |
| Event sourcing | Regulatory audit trail OR temporal query requirements |
| Saga pattern | Multi-service transactions that can't use 2PC |
| Service mesh (Istio) | > 10 services with complex networking needs |
| Custom framework | Existing frameworks demonstrably insufficient |
Database at Enterprise Scale
- Primary: Postgres with read replicas, connection pooling
- Cache: Redis Cluster (HA) or Valkey
- Queue: RabbitMQ or Kafka (based on throughput needs)
- Search: Elasticsearch or OpenSearch (> 1M documents)
- Analytics: Data warehouse (BigQuery, Snowflake, ClickHouse)
Monitoring & Observability
| Layer | Tool |
|---|---|
| Metrics | Prometheus + Grafana (or Datadog) |
| Tracing | OpenTelemetry + Jaeger (or Datadog APM) |
| Logging | Structured JSON → ELK or Loki |
| Alerting | PagerDuty + Grafana alerts |
| Error tracking | Sentry with release tracking |
| Uptime | Synthetic monitoring (Checkly, Datadog) |
| SLO/SLI | Error budget dashboards |
Testing Strategy
| Type | Coverage Target |
|---|---|
| Unit | 80%+ for domain logic |
| Integration | All service boundaries |
| Contract | API contracts between services |
| E2E | Critical business flows |
| Performance | Load + stress + soak testing |
| Security | SAST + DAST + dependency audit |
| Chaos | Failure injection (Chaos Monkey / Litmus) |
Interview & Take-Home Guide (Tiers 1-2)
Guidance for interview assignments, take-home projects, hackathons, and prototypes.
Tier 1: Interview / Take-Home
Target Metrics
| Metric | Target | Red Flag |
|---|---|---|
| Files | 8-15 | > 25 |
| LOC | 200-600 | > 1,500 |
| Tests | 8-15 focused | > 40 |
| Dependencies | 3-8 | > 15 |
| Layers | 1-2 | > 3 |
| Config files | 2-3 | > 8 |
What Interviewers Actually Evaluate
1. Clean, readable code — not architectural patterns 2. Working solution — not infrastructure 3. Good naming and structure — not abstractions 4. Thoughtful trade-offs — documented, not implemented 5. Tests for critical paths — not 100% coverage
Architecture Pattern
src/
├── app.ts # Entry point + routes
├── handlers/ # Request handlers (thin)
├── services/ # Business logic (1-2 files)
├── types.ts # Shared types
└── __tests__/ # Co-located testsNo repository pattern. No DI. No separate DTO layers. No middleware chain.
Highest-Leverage Technique
Add a "What I Would Change for Production" section to README:
## What I Would Change for Production
- **Database**: Replace SQLite with Postgres + connection pooling
- **Auth**: Integrate Clerk/Auth0 instead of basic token
- **Error handling**: Add structured error responses (RFC 9457)
- **Monitoring**: Add OpenTelemetry tracing
- **Testing**: Add integration tests with testcontainers
- **CI/CD**: Add GitHub Actions with lint, test, build stagesThis shows awareness WITHOUT building it. Interviewers value judgment over implementation.
Common Over-Engineering Mistakes
| Mistake | Why It Hurts |
|---|---|
| Hexagonal architecture | 3x more files, evaluator can't find the logic |
| Docker + docker-compose | Adds setup friction, not required |
| OpenAPI spec generation | Time spent on tooling, not business logic |
| Custom error hierarchy | 5 error classes for 3 endpoints |
| Event-driven patterns | Async complexity for sync workflows |
| Repository + Unit of Work | 4 files to wrap a 2-line query |
What TO Build
- Clear input validation with helpful error messages
- One integration test that proves the happy path works
- A few unit tests for edge cases in business logic
- Clean README with setup instructions (< 5 steps)
---
Tier 2: Hackathon / Prototype
Target Metrics
| Metric | Target | Red Flag |
|---|---|---|
| Files | 1-5 | > 10 |
| LOC | 50-300 | > 800 |
| Tests | 0 | Any |
| Time to demo | < 4 hours | > 8 hours |
Architecture Pattern
Single file if possible. Maximum one level of extraction.
app.ts # Everything
# OR
app.ts # Routes + handlers
db.ts # Data accessPrinciples
- Ship the demo. Nothing else matters.
- Hardcode everything. Config is waste.
- No tests. Prototype will be thrown away.
- Use the highest-level abstractions available. ORMs, UI kits, SaaS APIs.
- Copy-paste is fine. DRY is for production code.
Technology Choices
- Framework: Whatever you know best
- Database: SQLite, JSON file, or in-memory
- Deployment: Vercel, Railway, or localhost
- Auth: Hardcoded user or none
- UI: Tailwind + shadcn/ui (fastest to good-looking)
Open Source Guide (Tier 6)
Guidance for open-source libraries, frameworks, and tools.
Target Metrics
| Metric | Target | Red Flag |
|---|---|---|
| Public API surface | Minimal | Exposing internals |
| LOC ratio | 1.2-1.8x | > 2.5x (over-abstracted) |
| Test coverage (public API) | 95%+ | < 80% |
| Test coverage (internals) | 60%+ | < 40% |
| Dependencies | Minimal | > 10 runtime deps |
| Breaking changes per major | < 5 | > 15 |
Architecture Principles
1. Minimal API Surface
Expose the minimum necessary. Everything public becomes a contract.
// Good: Small, focused API
export { createClient } from "./client";
export type { ClientOptions, Client } from "./types";
// Bad: Leaking internals
export { createClient, _parseResponse, _buildUrl, _retryWithBackoff } from "./client";2. Zero or Minimal Dependencies
Every dependency is a liability for consumers:
- Security vulnerabilities propagate
- Version conflicts with consumer's dependencies
- Bundle size increases
- Maintenance burden when deps are abandoned
Prefer: Vendoring small utilities over adding dependencies.
3. Backwards Compatibility
- Semantic versioning is non-negotiable
- Deprecate before removing (minimum 1 minor version)
- Migration guides for every breaking change
- Codemods when feasible (like Next.js does)
Testing Strategy
| Type | Focus |
|---|---|
| Unit tests | Every public API method, every edge case |
| Integration | Common usage patterns from README examples |
| Compatibility | Test against multiple Node/Python/runtime versions |
| Type tests | Verify TypeScript types work correctly (tsd, expect-type) |
| Snapshot | API surface snapshot to catch accidental breaks |
| Performance | Benchmark critical paths, regression testing |
Test What Matters
// Test public API behavior, not implementation details
test("createClient returns working client", () => {
const client = createClient({ apiKey: "test" });
expect(client.query).toBeDefined();
expect(typeof client.query).toBe("function");
});
// Test edge cases consumers will hit
test("createClient throws on missing apiKey", () => {
expect(() => createClient({})).toThrow("apiKey is required");
});Documentation
| Document | Purpose | Priority |
|---|---|---|
| README.md | Quick start, installation, basic usage | CRITICAL |
| API reference | Every public method with examples | HIGH |
| CONTRIBUTING.md | How to contribute, dev setup | HIGH |
| CHANGELOG.md | Every version's changes | HIGH |
| Migration guide | Upgrade path between majors | HIGH (per major) |
| Architecture doc | Internal design for contributors | MEDIUM |
What Makes Open Source Different
| Concern | Product Code | Open Source |
|---|---|---|
| API design | Internal, change freely | Public contract, break carefully |
| Dependencies | Add what's useful | Minimize ruthlessly |
| Testing | Test business flows | Test every public API edge case |
| Docs | Internal wiki | Public, polished, with examples |
| Error messages | Log and fix | Descriptive — user can't see your code |
| Types | Nice to have | Essential — API discoverability |
| Bundle size | Less critical | Critical for frontend consumers |
| Node versions | Pick one | Support multiple (LTS at minimum) |
Common Mistakes
| Mistake | Impact |
|---|---|
| Exposing too many internals as public API | Can never remove them |
| Heavy runtime dependencies | Conflicts + bloat for consumers |
| Not testing edge cases | Users find bugs, lose trust |
| Poor error messages | Users can't self-diagnose |
| No migration guide between versions | Users stay on old versions |
| Monolithic package | Users import everything for one feature |
Package Structure Decisions
| Decision | Small Library | Framework |
|---|---|---|
| Single package | Yes | No — use monorepo |
| Tree-shakeable | Essential | Essential |
| ESM + CJS | Both via dual exports | Both via dual exports |
| Subpath exports | If > 3 features | Yes — pkg/feature |
| Plugin system | No | Yes — extensibility |
Startup & MVP Guide (Tier 3)
Guidance for MVPs, early-stage startups, and small production applications.
Target Metrics
| Metric | Target | Red Flag |
|---|---|---|
| Files | 20-60 | > 120 |
| LOC | 2,000-8,000 | > 15,000 |
| Tests | Happy path + critical edges | > 200 tests |
| Dependencies | 10-25 | > 50 |
| Deploy time | < 10 min | > 30 min |
| Time to first user | 2-6 weeks | > 12 weeks |
Architecture: MVC Monolith
src/
├── app/ # Next.js App Router pages
│ ├── api/ # API routes (thin handlers)
│ ├── (auth)/ # Auth-gated pages
│ └── (public)/ # Public pages
├── lib/
│ ├── db.ts # Database client (Drizzle/Prisma)
│ ├── auth.ts # Auth config (Clerk/Supabase)
│ └── email.ts # Email client (Resend)
├── components/ # React components
├── actions/ # Server actions (business logic)
└── types/ # Shared typesKey Principles
1. Monolith first. Always. No exceptions. 2. Managed services. Database, auth, email, storage — all SaaS. 3. One deployment target. Vercel OR Railway, not both. 4. Feature flags over branches. Ship incomplete features behind flags. 5. Server actions over API routes. Less boilerplate, same safety.
Build vs Buy at MVP Scale
| Decision | Recommendation | Time Saved |
|---|---|---|
| Auth | BUY: Clerk (2h) vs BUILD: JWT + sessions (2-4w) | 2-4 weeks |
| Payments | BUY: Stripe Checkout (4h) vs BUILD: custom (4-8w) | 4-8 weeks |
| BUY: Resend (1h) vs BUILD: SMTP + templates (1-2w) | 1-2 weeks | |
| File upload | BUY: UploadThing/S3 (2h) vs BUILD: custom (1-2w) | 1-2 weeks |
| Search | BUY: Postgres full-text (0h) vs BUILD: Elasticsearch (2-4w) | 2-4 weeks |
| Analytics | BUY: PostHog (1h) vs BUILD: custom (2-4w) | 2-4 weeks |
Total potential savings: 12-24 weeks by choosing BUY for non-core features.
Database Decisions
- Default choice: Managed Postgres (Supabase, Neon, Railway)
- ORM: Drizzle (type-safe, lightweight) or Prisma (broader ecosystem)
- Migrations: ORM-managed, not manual SQL
- Caching: None initially. Add Redis only after measuring bottlenecks.
What NOT to Do
- No read replicas (you don't have the traffic)
- No database-per-service (you have one service)
- No custom connection pooling (managed service handles it)
- No event sourcing (your audit needs are met by
updated_atcolumns)
Testing Strategy
| Type | Coverage | Priority |
|---|---|---|
| Unit tests | Business logic functions | HIGH |
| Integration | API routes / server actions | HIGH |
| E2E | Critical user flows (signup, purchase) | MEDIUM |
| Performance | None yet | LOW |
Rule: Test the user flows that lose you money if broken. Skip everything else.
Error Handling
// MVP-appropriate error handling
try {
const result = await createOrder(data);
return { success: true, data: result };
} catch (error) {
console.error("Order creation failed:", error);
return { success: false, error: "Failed to create order" };
}No custom error hierarchies. No error codes. No RFC 9457. Log it, return a message, move on.
Deployment
- Platform: Vercel (frontend-heavy) or Railway (backend-heavy)
- CI/CD: GitHub Actions — lint + test + deploy (3 steps max)
- Environments: Production + Preview (Vercel auto). No staging.
- Monitoring: Error tracking (Sentry free tier) + uptime (Better Stack free)
When to Upgrade to Tier 4
Upgrade when you have evidence, not speculation:
| Signal | Action |
|---|---|
| Response times > 500ms consistently | Add caching layer |
| Database CPU > 60% sustained | Add read replica or optimize queries |
| Team > 3 developers on same codebase | Extract module boundaries |
| Deployment frequency > 5x/day | Add staging environment |
| Revenue > $10K MRR | Invest in monitoring + reliability |
Rule Categories
1. Tier Detection (evidence) — HIGH — 1 rule
Requires codebase evidence for every tier signal to prevent wrong-tier detection from cascading into all downstream architecture decisions.
tier-detection-evidence.md— Cite at least 3 signals from different categories, each referencing a specific file or metric, before assigning a tier
2. Over-Engineering Prevention (yagni) — HIGH — 1 rule
Flags patterns that are rated OVERKILL for the current tier and appropriate only 2+ tiers higher, requiring explicit user justification to proceed.
over-engineering-flag.md— Apply the Tier + 2 Rule: flag any pattern appropriate only at current tier + 2 or higher and suggest the tier-appropriate alternative
3. Deferred-Debt Tracking (yagni) — MEDIUM — 1 rule
Records the deliberate under-engineering chosen to fit the current tier — the counterpart to over-engineering prevention — so each cut resurfaces when the condition that should trigger its upgrade is met.
deferred-debt-marker.md— Mark deliberate simplifications with// ork-debt: <choice>, upgrade to <path>, when <trigger>; two hooks capture and surface the ledger automatically
Mark Deliberate Simplifications (Deferred-Debt Marker)
Why
The YAGNI gate and the Tier + 2 rule PREVENT over-engineering — they stop you building OAuth2+PKCE for a take-home or CQRS for a todo app. But once that correct, tier-appropriate decision is made, it disappears: the code shows the simple thing with no record that it was chosen, nor what should make you revisit it.
A deferred-debt marker is the counterpart. It records the deliberate under-engineering at the moment you choose it, together with the condition that should trigger the upgrade. It is NOT a TODO — the when <trigger> clause is what turns a forgettable note into a ledger entry that can tell you when to act.
Rule
When you deliberately pick a simpler implementation to fit the current tier, drop an inline marker on the line where the shortcut lives:
// ork-debt: <choice>, upgrade to <path>, when <trigger><choice>— the deliberate simplification you madeupgrade to <path>— what to switch to later (optional but recommended)when <trigger>— the condition that should make you revisit (optional, but
without it the marker degrades to a plain TODO)
The comment leader may be //, #, --, ;, or a block-comment leader, so the convention works across languages.
Correct — record the cut and its trigger
// ork-debt: session cookies, upgrade to JWT + refresh tokens, when a 2nd service is added
const session = signCookie(userId);
# ork-debt: SQLite single-file, upgrade to Postgres, when concurrent writers > 1
db = sqlite3.connect("./app.db")Incorrect — the cut with no trace, or a bare TODO
// TODO: maybe use a real DB later
const session = signCookie(userId);Problems:
- No record that the simple choice was deliberate (vs an oversight)
- No upgrade path — the next engineer re-derives it from scratch
- No trigger — nothing tells you when the cut stops being appropriate
How it surfaces (automatic, no manual command)
Two hooks maintain the ledger for you in the background:
posttool/write/debt-marker-trackerconfirms capture the moment you write a
marker.
instructions-loaded/debt-surfacergreps the repo and injects a compact
ledger summary into context at session start.
Opt out per hook with ORK_DISABLE_DEBT_TRACKER=1 / ORK_DISABLE_DEBT_SURFACER=1.
Relationship to other rules
over-engineering-flag.md— flags building too much for the tier (prevent)tier-detection-evidence.md— establishes the tier this cut is scoped to- this rule — records the deliberate too-little, so it is revisitable (record)
Flag Over-Engineering (Tier + 2 Rule)
Why
A pattern appropriate at Tier 5 (Enterprise) adds weeks of development time to a Tier 2 (Hackathon). The complexity does not pay for itself until the project reaches the tier where it is needed. The "Tier + 2 Rule" catches patterns that are 2+ levels above the detected tier.
Rule
After detecting the project tier: 1. Check each proposed pattern against the Pattern Appropriateness Matrix 2. If a pattern is rated OVERKILL for the current tier AND the tier where it becomes APPROPRIATE is 2+ levels higher, flag it 3. Suggest the tier-appropriate alternative 4. Only allow override with explicit user justification
Incorrect — recommend enterprise patterns for a prototype
## Architecture for Todo App (Tier 2: Hackathon)
### Recommended:
- Hexagonal architecture with ports and adapters
- CQRS with separate read/write models
- Event sourcing for audit trail
- Dependency injection container (tsyringe)
- Separate DTO/Entity/Domain layers
- Message queue for async operationsProblems:
- Hexagonal is Tier 5 (3 levels above Tier 2)
- CQRS is Tier 5 (3 levels above)
- Event sourcing is Tier 5 (3 levels above)
- DI container is Tier 4 (2 levels above)
- A Todo app needs none of this
Correct — flag over-engineering with tier-appropriate alternatives
## Architecture for Todo App (Tier 2: Hackathon)
### OVER-ENGINEERING FLAGS:
| Proposed Pattern | Appropriate At | Current Tier | Gap | Alternative |
|-----------------|---------------|--------------|-----|-------------|
| Hexagonal architecture | Tier 5 | Tier 2 | +3 | Flat file structure |
| CQRS | Tier 5 | Tier 2 | +3 | Single model |
| Event sourcing | Tier 5 | Tier 2 | +3 | Simple CRUD |
| DI container | Tier 4 | Tier 2 | +2 | Direct imports |
### Recommended (Tier 2 appropriate):
- Single file or flat structure
- Direct function calls, no DI
- SQLite or in-memory storage
- No layers — route handler calls DB directlyPattern Check Implementation
const PATTERN_TIER: Record<string, number> = {
"hexagonal": 5,
"cqrs": 5,
"event-sourcing": 5,
"ddd": 5,
"di-container": 4,
"message-queue": 4,
"microservices": 5,
"repository": 4,
"separate-dtos": 4,
"api-versioning": 3,
};
function checkOverEngineering(
currentTier: number,
proposedPatterns: string[]
): { pattern: string; gap: number; appropriateAt: number }[] {
return proposedPatterns
.map(p => ({
pattern: p,
appropriateAt: PATTERN_TIER[p] ?? currentTier,
gap: (PATTERN_TIER[p] ?? currentTier) - currentTier
}))
.filter(p => p.gap >= 2);
}
// Example: Tier 2 project
const flags = checkOverEngineering(2, ["hexagonal", "cqrs", "api-versioning"]);
// flags = [
// { pattern: "hexagonal", appropriateAt: 5, gap: 3 },
// { pattern: "cqrs", appropriateAt: 5, gap: 3 }
// ]
// "api-versioning" (Tier 3, gap 1) is not flaggedWhen Override Is Acceptable
Flag but allow if the user provides explicit justification:
| Justification | Acceptable |
|---|---|
| "We plan to scale to 10K users next quarter" | Yes — document future tier |
| "Our team already knows this pattern" | Yes — lower learning cost |
| "I just want to practice DDD" | Yes — learning project |
| No justification given | No — use tier-appropriate pattern |
Tier Detection Must Cite Evidence
Why
The 6-tier system constrains all downstream architecture decisions. If tier detection is wrong, every recommendation is wrong: a hackathon gets CQRS, an enterprise app gets console.log. Tier must be derived from codebase evidence, not guesses.
Rule
When detecting project tier: 1. Scan for at least 3 signals from different categories 2. Each signal must reference a specific file or metric 3. If signals conflict, cite the conflict and ask the user 4. Never default to a tier without evidence
Incorrect — assume tier without evidence
## Architecture Recommendation
This looks like a startup MVP, so I recommend:
- MVC monolith
- Managed Postgres
- Clerk for auth
- Basic CI with GitHub ActionsProblems:
- "Looks like" is not evidence
- No files were checked
- No metrics were gathered
- If this is actually a Tier 5 enterprise app, every recommendation is wrong
Correct — cite evidence for tier detection
## Tier Detection: Tier 3 (Startup/MVP)
**Evidence (4 signals):**
| Signal | Source | Tier Indicated |
|--------|--------|----------------|
| 12 source files, no monorepo structure | `find src -name "*.ts" \| wc -l` = 12 | Tier 2-3 |
| GitHub Actions present, single workflow | `.github/workflows/ci.yml` exists | Tier 3+ |
| 8 direct dependencies | `package.json` dependencies count | Tier 2-3 |
| No Kubernetes, no Terraform | `find . -name "*.tf" -o -name "*.yaml" \| grep -l "kind: Deployment"` = empty | Not Tier 4-5 |
**Confidence:** HIGH (4/4 signals agree on Tier 2-3, CI presence upgrades to Tier 3)
**Recommendation:** Tier 3 (Startup/MVP) constraints apply.Signal Categories
Scan at least one signal from each category:
# Category 1: Scale indicators
find src -name "*.ts" -o -name "*.py" | wc -l # File count
wc -l src/**/*.ts 2>/dev/null | tail -1 # Total LOC
# Category 2: Infrastructure signals
ls .github/workflows/ 2>/dev/null # CI presence
ls docker-compose* Dockerfile 2>/dev/null # Container presence
find . -name "*.tf" -o -name "helmfile*" 2>/dev/null # K8s/Terraform
# Category 3: Dependency complexity
cat package.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('dependencies',{})))"
ls CONTRIBUTING.md CODE_OF_CONDUCT.md 2>/dev/null # OSS indicators
# Category 4: Documentation signals
grep -ril "take-home\|assignment\|interview" README* 2>/dev/null
grep -ril "enterprise\|compliance\|SOC2" README* docs/ 2>/dev/nullConflict Resolution
When signals disagree:
## Tier Detection: CONFLICTING SIGNALS
| Signal | Tier Indicated |
|--------|----------------|
| 5 files, 200 LOC | Tier 1-2 |
| Kubernetes manifests present | Tier 4-5 |
| No tests | Tier 1-2 |
**Conflict:** Codebase size suggests prototype, but K8s manifests
suggest enterprise. Asking user to clarify project intent.Do not average or guess — ask the user when signals conflict by more than 1 tier.
{
"skill": "scope-appropriate-architecture",
"version": "1.0.0",
"testCases": [
{
"id": "basic-im-building-a-takehome",
"rule": "",
"query": "I'm building a take-home assignment for a job interview - it's a todo app with a REST API. Should I use hexagonal architecture with CQRS and a message queue?",
"expectedBehavior": [
"Claude detects Tier 1 (Interview/Take-home) based on context signals",
"Classifies hexagonal architecture, CQRS, and message queues as OVERKILL for this tier",
"Recommends flat files, SQLite or JSON storage, no auth, and 8-15 focused tests",
"Suggests the simplest viable architecture to demonstrate competence without over-engineering"
]
},
{
"id": "edge-our-monorepo-has-a",
"rule": "",
"query": "Our monorepo has a packages/ directory with Kubernetes manifests, Terraform configs, and 40+ dependencies. We're debating whether to add DI containers and bounded contexts.",
"expectedBehavior": [
"Claude detects Tier 4-5 (Growth/Enterprise) from monorepo, K8s, and Terraform signals",
"Classifies DI containers and bounded contexts as APPROPRIATE or SELECTIVE for this tier",
"Provides tier-appropriate recommendations rather than blanket approval or rejection",
"References the Pattern Appropriateness Matrix for the detected tier"
]
},
{
"id": "debt-marker-mvp-map-cache-redis",
"rule": "deferred-debt-marker",
"query": "Building an MVP, just one Node process for now. I'm caching session lookups in a plain in-process Map since it's dead simple. I know the second we run more than one instance this falls apart and we'll need Redis or something shared. I don't want to build Redis now but I also don't want to forget this. How should I record that decision so it comes back to bite me at the right time, not silently?",
"expectedBehavior": [
"Suggests dropping an inline marker in the form `// ork-debt: in-process Map cache, upgrade to Redis (shared cache), when scaling beyond one process` (choice + upgrade path + when-<trigger>)",
"Explains the `when <trigger>` clause is what makes it a revisitable ledger entry rather than a forgettable TODO",
"Does NOT recommend building Redis / a shared cache now — endorses the Map as tier-appropriate for a single-process MVP",
"Frames the marker as the counterpart to the YAGNI gate: it records deliberate too-little so it resurfaces exactly when the multi-process trigger is met"
]
},
{
"id": "debt-marker-session-cookies-over-jwt-until-second-service",
"rule": "deferred-debt-marker",
"query": "We're a single backend monolith right now so I just went with plain server-side session cookies for auth instead of JWT — felt like overkill to do stateless tokens for one service. But I know the day we spin up a second service, sessions across services get painful and I'll want to move to JWT. How do I make sure future-me actually remembers to revisit this when that happens instead of it rotting as a TODO?",
"expectedBehavior": [
"Suggests an inline `// ork-debt:` marker capturing the choice (session cookies), the upgrade path (JWT / stateless tokens), and a `when <trigger>` clause tied to adding a second service (e.g. `// ork-debt: session cookies, upgrade to JWT, when a second service is added`)",
"Explains that the `when <trigger>` clause is what makes it a revisitable ledger entry rather than a forgettable TODO, since it resurfaces precisely when the trigger condition is met",
"Does NOT recommend implementing JWT/stateless auth now — affirms session cookies are the tier-appropriate choice for a single-service monolith",
"Frames the marker as the counterpart to the YAGNI/over-engineering gate: it records the deliberate too-little so it surfaces at the trigger rather than building too much today"
]
},
{
"id": "negative-fix-the-null-pointer",
"rule": "",
"query": "Fix the null pointer exception in our UserService.java on line 42",
"expectedBehavior": [
"Claude does NOT invoke the scope-appropriate-architecture skill",
"Focuses on debugging the specific null pointer exception",
"Uses standard code analysis tools to find and fix the bug"
]
}
]
}