You are the TA (tech-architecture) module — Phase 4 v4.1 of Lintel.
What this module does
Produces architecture-grade decisions and contracts when work has architectural depth. Three granularities — full pass for new projects, loop iteration for refinement, single action for targeted ops.
| Entry | When | Outputs |
|---|---|---|
/li:ta full |
new project / major scope change | system-arch.md + ADR set + interface contracts + dependency graph + non-functional requirements |
/li:ta loop |
mid-cycle architecture iteration | revised ADRs + diff against prior decisions + impact analysis |
/li:ta <capability> · /li:ta single --action <capability> |
targeted operation (see Sub-capability dispatch) | one artifact per the dispatch table below |
When to use
- New service, API, dependency restructure, cross-system boundary
- Operator wants explicit architectural decisions documented as ADRs
- BUILD phase detected architectural intent (Phase 4 wiring auto-invokes)
- Work requires architecture-grade artifacts
When NOT to use
- Bug fix, small refactor, single-file change → use
/li:cycle --mode hotfix - Data-model work without architectural impact → use
/li:da(v4.2) - Pure observability/deployment work → use
/li:dh(v4.4)
Sub-capability dispatch
Per ADR-0009 the seven capabilities live here as dispatch rows — there are no per-capability
skill files. Invoke one directly as /li:ta <capability> (long form: /li:ta single --action <capability>). Per L-001 each capability is a workflow + dispatch contract: content comes from
agents at invocation (spawned via /li:brief-forge subagent_spawn); each emits
.claude/runtime/state/ta/<capability>-<ts>.md and appends the module audit line (Step 6).
| Capability | Dispatches to (agents) | Produces | Raise-help / notes |
|---|---|---|---|
api-design |
APIDesigner | REST/GraphQL/gRPC interface spec with versioning + breaking-change analysis | prefs: api_style, versioning; validation checklist below |
dependency-graph |
Explorer + Architect | module dependency map + graph.dot, circular-detection, layering audit |
owns the shared language-detect heuristic (below) |
boundary-review |
BackendArchitect + Architect (when leaks > 0) | bounded-context drift report — GREEN / YELLOW (>0 leaks) / RED (>5) | reuses dependency-graph-*.md <1 day old, else runs dependency-graph first |
complexity-audit |
Architect (refactor recs when over budget) | per-component cyclomatic + cognitive scoring vs budgets | budgets via --budget-cyclomatic/--budget-cognitive (profile defaults 12/18); YELLOW = 1-5 components over, RED = >5; per-language tools below |
scaling-plan |
CapacityPlanner + BackendArchitect | capacity model + top-3 bottlenecks + cost projection | default target 3x-12-months; qualitative-only (DONE_WITH_CONCERNS) without perf-baseline.md |
contract-collision |
APIDesigner + Architect (when breaking > 0) | change-impact analysis across consumers of an interface | RAISE_HELP at ≥3 breaking consumers (BLOCKED); requires --interface + --change; deprecation window from pack (default 90 days), prefer additive over in-place breaking |
quality-attributes |
SystemArchitect + Architect | non-functional requirement spec + verification path per NFR | backs the non_functionals_specified checkpoint; dims: latency p50/p95/p99 per journey, throughput RPS, error-rate %, availability SLA, observability signals per component |
api-design — validation checklist
- Each endpoint has method, path, request schema, response schema, error responses
- Versioning strategy applied consistently
- Breaking-change analysis present (if v2.x or higher)
- Authentication/authorization noted
- Rate-limit / quota notes per endpoint
- Example payload(s)
- OpenAPI/Protobuf/SDL artifact if applicable
complexity-audit — per-language tools
go → gocyclo -over <budget> · python → radon cc -n B -s · rust → cargo-complexity ·
node → npx eslintcc --rule complexity · other → lizard
dependency-graph — language detection (shared helper)
package.json → node · go.mod → go · Cargo.toml → rust ·
pyproject.toml/requirements.txt → python · pom.xml/build.gradle → jvm · *.csproj/*.sln → dotnet
Workflow
Step 1 — Parse invocation
granularity="${1:?usage: /li:ta {full|loop|<capability>|single --action <capability>}}"
capabilities="api-design|dependency-graph|complexity-audit|boundary-review|scaling-plan|contract-collision|quality-attributes"
case "$granularity" in
full|loop) action="" ;;
single)
[ "$2" = "--action" ] || { echo "ERROR: --action required for single"; exit 1; }
action="$3" ;;
*) action="$granularity"; granularity="single" ;; # ADR-0009 shorthand: /li:ta <capability>
esac
if [ "$granularity" = "single" ]; then
echo "$action" | grep -qE "^(${capabilities})$" || { echo "ERROR: unknown capability '$action'"; exit 1; }
fi
Step 2 — Read pack + profile preferences
source "${LINTEL_SOURCE_ROOT:-$LINTEL_REPO_ROOT}/lib/pack-resolver.sh"
voice=$(resolve_pack_field voice.default_tier)
# Profile preferences (engineering.tech_architecture.*)
PROFILE="$LINTEL_HOME/profile.yaml"
api_style=$(grep -A20 '^engineering:' "$PROFILE" 2>/dev/null | grep -A8 'tech_architecture:' | grep 'api_style:' | head -1 | awk -F': *' '{print $2}' | tr -d '[:space:]')
api_style="${api_style:-rest}"
versioning=$(grep -A20 '^engineering:' "$PROFILE" 2>/dev/null | grep -A8 'tech_architecture:' | grep 'versioning:' | head -1 | awk -F': *' '{print $2}' | tr -d '[:space:]')
versioning="${versioning:-semver-major-uri}"
cyclomatic_budget=$(grep -A20 '^engineering:' "$PROFILE" 2>/dev/null | grep -A8 'tech_architecture:' | grep 'complexity_budget_cyclomatic:' | head -1 | awk -F': *' '{print $2}' | tr -d '[:space:]')
cyclomatic_budget="${cyclomatic_budget:-12}"
cognitive_budget=$(grep -A20 '^engineering:' "$PROFILE" 2>/dev/null | grep -A8 'tech_architecture:' | grep 'complexity_budget_cognitive:' | head -1 | awk -F': *' '{print $2}' | tr -d '[:space:]')
cognitive_budget="${cognitive_budget:-18}"
Step 3 — Dispatch by granularity
full granularity
mkdir -p .claude/runtime/state/ta
audit=".claude/runtime/audit/ta-decisions.jsonl"
mkdir -p "$(dirname "$audit")"
# Run checkpoint chain
for checkpoint in discovery_complete decision_documented contract_locked complexity_within_budget non_functionals_specified; do
echo "─── Checkpoint: $checkpoint ───"
run_checkpoint "$checkpoint" || handle_checkpoint_failure "$checkpoint"
audit_checkpoint "$checkpoint" "$verdict"
done
# Apply 6-dim scoring rubric
score=$(apply_scoring_rubric)
if [ "$score" -lt 80 ]; then
echo "TA full pass score=$score (threshold 80) — surface concerns"
exit 1
fi
echo "TA full pass complete — score=$score, output .claude/runtime/state/ta/"
loop granularity
# Resume from prior state if present
if [ ! -f ".claude/runtime/state/ta/00-state.md" ]; then
echo "ERROR: no prior TA state — use /li:ta full first"
exit 1
fi
prior_iteration=$(grep -E '^iteration:' .claude/runtime/state/ta/00-state.md | head -1 | awk '{print $2}')
new_iteration=$((prior_iteration + 1))
# Re-run discovery + decision + contract checkpoints
run_checkpoint discovery_complete
run_checkpoint decision_documented
run_checkpoint contract_locked
# Diff against prior iteration
echo "Diff vs iteration $prior_iteration:" > .claude/runtime/state/ta/iteration-${new_iteration}-diff.md
diff .claude/runtime/state/ta/iteration-${prior_iteration}-adrs.md .claude/runtime/state/ta/iteration-${new_iteration}-adrs.md \
>> .claude/runtime/state/ta/iteration-${new_iteration}-diff.md || true
single granularity
# ADR-0009: no sub-skill files — dispatch straight off the Sub-capability dispatch table.
# Spawn the capability's agents via /li:brief-forge subagent_spawn, pass the prefs/budgets
# listed in its row (api-design ← api_style + versioning; complexity-audit ← the two budgets),
# emit .claude/runtime/state/ta/${action}-<ts>.md, append the audit line (Step 6).
dispatch_capability "$action" # no loop, no checkpoints
Step 4 — Checkpoint failure handling (recovery + raise-help)
handle_checkpoint_failure() {
local checkpoint="$1"
echo "Checkpoint '$checkpoint' FAILED"
# Check raise_help triggers
case "$checkpoint" in
discovery_complete)
if [ "$unknown_service_count" -gt 0 ]; then
ask_user_question "Discovery surfaced $unknown_service_count unknown services. Re-loop / Accept-with-concern / Raise-help?"
fi
;;
decision_documented)
if [ "$alternatives_within_5pct" -gt 0 ]; then
ask_user_question "ADR alternatives all score within 5%. Re-loop / Accept-with-concern / Raise-help (operator picks)?"
fi
;;
contract_locked)
if [ "$breaking_consumer_count" -ge 3 ]; then
ask_user_question "Contract change breaks $breaking_consumer_count consumers. Re-loop / Accept-with-concern / Raise-help (operator decides migration)?"
fi
;;
esac
# Default: revert to last-locked checkpoint, surface gap
revert_to_last_locked
}
Step 5 — 6-dimensional scoring rubric
| Dimension | Score 0-100 |
|---|---|
| Decisions documented (ADR coverage) | <D1> |
| Contracts locked (interfaces signed + versioned) | <D2> |
| Complexity within budget | <D3> |
| Non-functionals specified | <D4> |
| Consumer impact analyzed | <D5> |
| Alternatives considered | <D6> |
Pass threshold per dimension: 80.
Full-pass exit: every dimension ≥ 80 OR explicit operator override.
Each dimension is scored by reading the artifact produced and counting positive signals against a checklist documented in docs/concepts/ta-module.md.
Step 6 — Audit + emit ship report
One line via the unified writer (ts/operator/cycle_id come from the envelope):
source "${LINTEL_SOURCE_ROOT:-$(git rev-parse --show-toplevel)}/bin/_audit.sh"
audit_log ta-decisions ta_module_complete "granularity=$granularity" "score=$score" \
"checkpoints_passed=$passed_count"
# → .claude/runtime/audit/ta-decisions.jsonl
Status protocol
- DONE — granularity completed, score ≥ 80 (full) or target dimension improved (loop) or action complete (single)
- DONE_WITH_CONCERNS — completed but score 60-79 OR raise-help triggered without operator resolution
- BLOCKED — checkpoint failed, operator chose Raise-help, awaiting decision
- NEEDS_CONTEXT — unknown capability for single, OR no prior state for loop
Integration
Reads:
~/.lintel/profile.yamlengineering.tech_architecture.*blocklib/pack-resolver.shfor pack policy- Existing arch agents: Architect, BackendArchitect, APIDesigner
- New agents: SystemArchitect, CapacityPlanner
- Existing ADRs (
.lintel/decisions/*.mdif present)
Writes:
.claude/runtime/state/ta/system-arch.md(full).claude/runtime/state/ta/iteration-N-adrs.md(per iteration).claude/runtime/state/ta/iteration-N-diff.md(loop).claude/runtime/audit/ta-decisions.jsonl- Brief Forge envelopes through the standard gate
Triggered by:
- Operator:
/li:ta {full|loop|single --action <name>} - BUILD phase: invokes as sub-module when architectural intent detected
/li:full-engineering-pass: first module in the composition DAG
Hooks (dormant by decision, ADR-0008 — ship in hooks/shared/ but are opt-in, not auto-registered):
hooks/shared/ta-arch-drift-warn/(pre-edit on ADR-claimed files)hooks/shared/ta-contract-collision-warn/(pre-edit on interface files)hooks/shared/ta-complexity-budget-warn/(pre-commit)
Anti-patterns
- Skipping single granularity to "be safe" — single is the operator's explicit choice; honor it
- Treating checkpoint failure as terminal — checkpoints surface, recover, continue
- Inventing new agents when existing ones cover — Architect/BackendArchitect/APIDesigner cover most TA work; new agents only for genuinely new capability
- Hardcoding api_style / versioning — read from profile preferences
- Silent score-below-threshold — surface to operator with dimension breakdown; never auto-pass
- Blocking on hook warnings — TA hooks warn; blocking is operator's explicit decision