TeamLead TECH Development Skill

SkillDatabases & data

Infrastructure and TECH task development using TDD workflow. Use when: develop TECH task, setup infrastructure, configure Docker, setup CI/CD, database migrations, or the user says "/nacl-tl-dev TECH###". Note: For UC backend tasks use /nacl-tl-dev-be, for frontend use /nacl-tl-dev-fe.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the TeamLead TECH Development Skill skill

What this skill tells your AI

The instructions your AI receives, as published by itsalt/nacl in nacl-tl-dev/SKILL.md and read by ahel’s review.

Contract

Inputs this skill consumes:

  • TECH task spec (TECH###)
  • Workspace package.json scripts.test (Workflow A — TDD path) OR verification command from README/task spec (Workflow B — infra path)

Outputs this skill produces:

  • Headline one of: DEV COMPLETE / DEV APPLIED — UNVERIFIED / DEV APPLIED — BLOCKED / DEV APPLIED — NO_INFRA / DEV APPLIED — RUNNER_BROKEN / DEV INCOMPLETE — REGRESSION
  • Baseline diff (failures pre vs post the change)
  • Test or verification-command output snippet

Downstream consumers of this output:

  • nacl-tl-review (TECH path)
  • nacl-tl-ship
  • nacl-tl-deliver
  • nacl-tl-conductor

Upstream dependency (Workflow A only):

  • nacl-tl-regression-test mode=feature-dev — writes test files in RED phase (A.2). This skill is strictly the implementation author (GREEN phase, A.4). Test authorship and implementation authorship are separated by construction. If the contract or failure-mode headers of nacl-tl-regression-test change, this skill must be audited in the same release.

Contract change discipline: The 0.10.0→0.10.1 regression was caused by the absence of this discipline. nacl-tl-fix changed its output contract (new status vocabulary, new header strings, new Status: field) without auditing nacl-tl-reopened and nacl-tl-hotfix, which were the only two skills that consume its output. Had a ## Contract section existed in nacl-tl-fix, the update would have included a list of downstream consumers, making the audit mandatory and visible. The ## Contract section is not a runtime mechanism — it does not add any automated enforcement. It is a documentation discipline that makes the contract explicit and the change-cost visible at authoring time. If this skill's output contract changes, every downstream consumer listed above must be audited and updated in the same release.


You are a senior developer implementing TECH (infrastructure/tooling) tasks. TECH tasks cover work that is not tied to a specific use case but is essential for the project to function:

  • Docker Compose setup
  • CI/CD pipeline configuration
  • Database migration scripts
  • Development environment setup
  • Linting / formatting configuration
  • Shared utilities and libraries

You work from self-sufficient task files created by nacl-tl-plan.

Your Role

  • Read task files from .tl/tasks/TECH-###/ directory
  • Follow TDD or verification workflow depending on task category
  • Write tests first when the task involves testable code
  • Run verification commands when the task involves infrastructure
  • Create result.md documenting your work
  • Update tracking files after completion

Key Principle: TECH Tasks Are Not UC Tasks

CRITICAL: TECH tasks differ from UC tasks in important ways:

  • TECH tasks have NO Actor, NO Input/Output, NO Main Flow
  • TECH tasks use tech-task-template.md format (not task-be or task-fe)
  • TECH tasks have type: "tech" in status.json
  • TECH tasks are always in Wave 0 (infrastructure first)
  • TECH task IDs: TECH-001, TECH-002, etc. (not UC001, BE-UC001, FE-UC001)

Flags

FlagDescription
TECH-###Task ID to implement (required)
--continueRe-work after review rejection (reads review.md)
--dry-runShow execution plan without making changes
--auto-shipAfter successful TDD cycle + green tests, automatically invoke /nacl-tl-ship (2.10.1+). Used by /nacl-goal intake to chain dev→ship without a per-skill confirmation. Behavior mirrors /nacl-tl-fix --auto-ship: PASS → ship; any non-PASS exit → STOP, the user makes the call.

Goal-context env vars (2.10.1+)

When this skill is invoked under /nacl-goal intake, the wrapper exports NACL_GOAL_RUN_ID, NACL_GOAL_BRANCH, NACL_SHIP_MODE=append, and NACL_GOAL_BUDGET_FILE. These propagate to /nacl-tl-ship (via --auto-ship) and trigger its append-mode behavior (goal-run branch push + single goal-run PR + pr.json write). See nacl-tl-ship/SKILL.md §Goal-context append mode for the full contract.

Also: when this skill writes a regression test for the TECH task per Step 3.2 (via /nacl-tl-regression-test), and the spec-first gate fires in any sub-invocation of /nacl-tl-fix, the exception lookup glob scans both .tl/exceptions/*.yaml AND .tl/exceptions/goal-runs/*/EXC-goal-*.yaml (see nacl-tl-fix/SKILL.md Step 6.SF rule 4).

Invariant: when these env vars are absent, this skill behaves exactly as today.

Pre-Development Checks

Before starting, verify:

  1. Task exists: .tl/tasks/TECH-###/task.md
  2. Task is ready: status.json shows status = "pending" or "in_progress"
  3. No blockers: status.json shows blockers = []
  4. Dependencies resolved: All dependent tasks are "done" or "approved"

If any check fails, report the issue and exit.

Task Files Structure

TECH tasks live in .tl/tasks/TECH-###/:

.tl/tasks/TECH-001/
  task.md         # TECH task description (tech-task-template.md format)
  test-spec.md    # Test specification (if applicable -- may not exist)
  impl-brief.md   # Implementation brief (if applicable -- may not exist)

Important: Unlike UC tasks, TECH tasks may not always have test-spec.md and impl-brief.md. For example, a Docker setup task does not need a test specification. Always check whether these files exist before attempting to read them.

Workflow

Step 1: Read Task Files

Read ALL available files for the task. Do NOT read original SA artifacts. Task files are self-contained.

Determine the task category from task.md frontmatter (category field):

CategoryWorkflowExamples
infraVerification-basedDocker, networking, volumes
databaseTDD or verificationMigrations, seed data, indexes
cicdVerification-basedGitHub Actions, linting CI
authFull TDDJWT, RBAC, session management
monitoringVerification-basedHealth checks, logging
otherDepends on scopeCode style, tooling, shared libs

Step 2: Update Status

Set task status to in_progress:

{
  "id": "TECH-###",
  "type": "tech",
  "status": "in_progress",
  "wave": 0,
  "started": "YYYY-MM-DDTHH:MM:SSZ"
}

Step 3: Choose Workflow

Based on the task category, follow either Workflow A (TDD) or Workflow B (verification-based).


Workflow A: Full TDD (for testable code)

Use when the task produces testable code: utility libraries, shared types with validation, auth middleware, database helpers, etc.

A.0: DISCOVER RUNNER

Read scripts.test from the affected workspace's package.json (the nearest package.json walking up from the files you will create or modify). If scripts.test is absent or package.json does not exist, halt with:

DEV APPLIED — NO_INFRA
scripts.test not found in workspace package.json. Test verification is not possible.
Recommend: open a TECH task to set up a test runner before implementing testable code.

A.1: CAPTURE BASELINE

Run scripts.test once before writing any test or production code. Capture and store:

  • The exact set of failing tests (file name + test name) → baseline_failures
  • Total tests collected, total passing, total failing
  • Whether the runner started cleanly (exit code, any stderr)

Store output in /tmp/TECH-###-baseline.txt (or equivalent temp location). This baseline is the reference for all subsequent comparisons.

If the runner crashes before any test runs → record RUNNER_BROKEN and continue (status will resolve at A.5).

A.2: RED Phase — Delegate Test Authorship (formerly A1)

Do NOT write test files yourself. Test authorship is separated from implementation authorship. Invoke nacl-tl-regression-test as a sub-agent (developer subagent_type) with:

/nacl-tl-regression-test
  mode=feature-dev
  task_id=TECH-###
  test_spec=.tl/tasks/TECH-###/test-spec.md
  acceptance=.tl/tasks/TECH-###/acceptance.md
  target_files=[<paths of source files the feature will live in — may not exist yet>]
  layer=tech

The sub-agent writes ONLY the test file. It verifies RED (the tests fail on the current codebase) and reports one of:

Sub-agent reportMeaningAction
FEATURE-TEST WRITTENTests written and confirmed REDProceed to A.4
FEATURE-TEST HALTED — NO_INFRANo scripts.test or no test-spec.mdHalt with DEV APPLIED — NO_INFRA; recommend TECH task to set up runner or spec
FEATURE-TEST INVALID — NOT REDTests pass on unimplemented code (test quality failure)Halt; ask user to sharpen test-spec.md and re-invoke
FEATURE-TEST FAILED TO REDSub-agent could not achieve RED for unrelated infra reasonHalt with DEV APPLIED — RUNNER_BROKEN

STOP here and do not proceed to A.4 unless the sub-agent reported FEATURE-TEST WRITTEN.

A.3: VERIFY RED (delegated — confirm sub-agent output)

RED verification is performed by the nacl-tl-regression-test sub-agent (see A.2 report). You do not re-run the test suite yourself in this step.

Confirm from the sub-agent's report:

(a) All test names from test-spec.md appear in the sub-agent's failure set. (b) The sub-agent confirms no previously-passing test was broken by the new test file.

If either is absent from the report, surface the discrepancy and halt before implementing.

The sub-agent commits RED:

git commit -m "test(TECH-###): add failing tests for [feature]"

(The sub-agent performs this commit. Do not duplicate it.)

A.4: GREEN Phase — Minimal Implementation (formerly A2)

  1. Write MINIMAL code to pass tests
  2. No premature optimization -- keep it simple
  3. Run tests after each change
  4. Stop when all tests pass

Commit GREEN:

git commit -m "feat(TECH-###): implement [feature]"

A.5: VERIFY GREEN + COMPARE

Run scripts.test once more (same command as A.1). Compute the delta against baseline:

ResultConditionStatus
New tests now passing AND postfix_failures ⊆ baseline_failures AND new_failures is emptyHappy pathPASS
New tests still failing (they did not transition)Change did not fix themUNVERIFIED
postfix_failures ⊃ baseline_failures (new failures introduced)Change broke somethingREGRESSION — halt before commit
Runner crashed or produced empty outputInfrastructure problemRUNNER_BROKEN
postfix_failures == baseline_failures AND change is in module A, all baseline failures are in unrelated module BPre-existing unrelated failuresBLOCKED with rationale

A.6: REFACTOR Phase — Improve Code (formerly A3)

  1. Improve code quality without changing behavior
  2. Extract common patterns, improve naming, remove duplication
  3. Run tests after EACH change -- tests MUST stay green

Refactoring Checklist:

  • Tests still pass
  • No duplication
  • Clear naming and single responsibility
  • Proper error handling
  • TypeScript strict mode passes
  • No ESLint warnings

Commit:

git commit -m "refactor(TECH-###): improve [component] implementation"

Workflow B: Verification-Based (for infrastructure)

Use when the task produces configuration: Docker setup, CI/CD pipelines, environment configuration, etc.

B.0: DISCOVER VERIFICATION COMMAND

Read the verification command from the task's task.md (Verification section) or from the project README. The command must be explicit (e.g., docker compose ps, terraform plan, make smoke, gh workflow list).

If no verification command is documented, halt with:

DEV APPLIED — NO_INFRA
No verification command found in task.md or README. Infrastructure verification is not possible.
Recommend: add a Verification section to task.md with a concrete command before implementing.

B.1: CAPTURE BASELINE STATE

Run the verification command once before applying any change. Capture:

  • Current running state (container names, statuses, exit codes)
  • Relevant config diff if applicable (e.g., docker compose config, terraform show)

Store in /tmp/TECH-###-baseline.txt. This is the reference for comparison after the change, and it feeds the verification record written in B.3.5 — do not discard it before that step.

B.2: Implement Configuration (formerly B1)

  1. Read task.md requirements and configuration section
  2. Read impl-brief.md if it exists
  3. Create or modify configuration files as specified in "Files to Create" / "Files to Modify"

Commit:

git commit -m "feat(TECH-###): configure [infrastructure component]"

B.3: RE-RUN VERIFICATION COMMAND

Run the same verification command as B.0. Sanity-check:

  • Output is non-empty
  • Exit code is zero (or the expected non-zero documented in task.md)
  • Expected containers/services/resources appear in the output

If output is empty or the command crashes → RUNNER_BROKEN. If expected resources are missing → treat as verification failure; return to B.2.

Fix cycle (formerly B3):

If verification reveals problems, fix configuration, re-run verification, repeat until all checks pass.

git commit -m "fix(TECH-###): resolve [issue] in [component]"

B.3.5: WRITE VERIFICATION RECORD (PASS only)

When B.3 completes cleanly (all expected resources present), write a durable verification record before producing the report. Console output alone is not evidence — the record is what the orchestrator forwards into the graph.

Path: .tl/tasks/TECH-###/verification.md (repo-relative, committed).

Content (all four sections mandatory):

# TECH-### — Infrastructure Verification Record

## Verification command
[the exact command from B.0, verbatim]

## Baseline (before change)
[output captured in B.1 — trim to the relevant resource lines]

## Post-change (after change)
[output from the final B.3 run — trim to the relevant resource lines]

## Resources verified
- [resource / container / service]: [expected state] — confirmed
- ...

Commit the record together with (or immediately after) the configuration:

git add .tl/tasks/TECH-###/verification.md
git commit -m "docs(TECH-###): verification record"

The repo-relative path of this file is the value the Regression test: line carries for a Workflow-B PASS (see the report contract below). If the record was not written, the task is NOT a PASS — return to B.3.

B.4: STATUS-AWARE OUTPUT

Determine status from B.3 result:

ResultStatusHeadline
Verification command ran cleanly, all expected resources present, verification record committed (B.3.5)PASSDEV COMPLETE
Verification command ran but expected resources missing / config mismatchInvestigate and fixReturn to B.2
Verification command crashed or produced empty outputRUNNER_BROKENDEV APPLIED — RUNNER_BROKEN
No verification command was documentedNO_INFRADEV APPLIED — NO_INFRA

Step N.6 — Status-Aware Output (both workflows)

After completing the TDD or verification cycle, produce output with the following headline based on the resolved status:

StatusHeadline
PASSDEV COMPLETE
UNVERIFIEDDEV APPLIED — UNVERIFIED
BLOCKEDDEV APPLIED — BLOCKED
NO_INFRADEV APPLIED — NO_INFRA
RUNNER_BROKENDEV APPLIED — RUNNER_BROKEN
REGRESSIONDEV INCOMPLETE — REGRESSION

Delegated-RED mapping (Workflow A): when nacl-tl-regression-test reports a failure mode, map it to this skill's status vocabulary before emitting the headline:

nacl-tl-regression-test reportThis skill's statusHeadline
FEATURE-TEST HALTED — NO_INFRANO_INFRADEV APPLIED — NO_INFRA
FEATURE-TEST INVALID — NOT REDNO_INFRADEV APPLIED — NO_INFRA (explain: test quality failure; sharpen test-spec.md)
FEATURE-TEST FAILED TO REDRUNNER_BROKENDEV APPLIED — RUNNER_BROKEN

Never use a single "Ready for Review" header. The headline must reflect the actual observed status.


--continue Flag: Re-Work After Review

When invoked with --continue, the agent re-works the task by delegating to /nacl-tl-fix. This skill no longer runs an inline test-after-change loop. The TDD/baseline/RED-first contract lives in nacl-tl-fix; this skill is a thin wrapper that builds the problem description, invokes the fix sub-agent, and propagates the resulting six-status into result.md and status.json.

Why delegation: the previous "apply the fix, run tests or verification" inline loop was test-after-change with no required RED-first test, no captured baseline, and no failure-set comparison — the same dishonesty class that triggered the 0.10.0 regression. /nacl-tl-fix already implements the hardened six-status contract; reusing it is the correct path. For TECH-tasks whose review issues are infrastructure-only (Workflow B applies and there is no testable code to regress against), the fix sub-agent resolves via its infrastructure verification path (Path C): it re-runs the task's documented verification command (baseline → fix → clean re-run), updates the committed .tl/tasks/TECH-###/verification.md record with a "Fix re-verification" section, and returns PASS with Regression test: verification: <path> — which orchestrators map to verify-GREEN:<path> evidence. NO_INFRA remains the honest outcome only when the task has no documented verification command at all; this skill records that rather than synthesising a PASS.

Continue Pre-Checks

  1. Review file exists: .tl/tasks/TECH-###/review.md
  2. Task status: Must be review_rejected
  3. Issues present: review.md must contain BLOCKER or CRITICAL issues

If review.md does not exist:

Error: No review file found for TECH-###

Expected: .tl/tasks/TECH-###/review.md

Run: /nacl-tl-review TECH### first to generate review feedback.

Continue Workflow (Delegation to /nacl-tl-fix)

1. Read .tl/tasks/TECH-###/review.md.
2. Parse issues by severity (BLOCKER / CRITICAL / MAJOR).
   Drop MINOR issues for the delegated invocation; they are captured in the
   final result.md note section.
3. Render each issue as a problem-description block:
     File: <path>:<line>
     Severity: <BLOCKER | CRITICAL | MAJOR>
     Description: <text>
     Suggestion: <text>
   Concatenate the blocks into a single problem-description string in
   priority order (BLOCKER → CRITICAL → MAJOR).
4. Invoke /nacl-tl-fix as a sub-agent:
     /nacl-tl-fix "<problem description>" --uc TECH-### --from-review
   The fix sub-agent owns:
     - runner discovery (its Step 7.1)
     - baseline capture (its Step 6b)
     - RED-first regression test via /nacl-tl-regression-test (its Step 6d–6e)
     - postfix run + set-difference (its Step 6g, 7.3)
     - six-status determination (PASS / BLOCKED / UNVERIFIED / NO_INFRA /
       RUNNER_BROKEN / REGRESSION)
   This skill does NOT write test files in --continue. The test-author
   isolation seam is preserved by /nacl-tl-fix invoking
   /nacl-tl-regression-test internally.
5. Read /nacl-tl-fix's report. Parse the authoritative classifier:
     Status: {PASS|BLOCKED|UNVERIFIED|NO_INFRA|RUNNER_BROKEN|REGRESSION}
   Headlines are advisory; the Status: line wins. A report without a
   parseable Status: line halts this skill as
   "DEV APPLIED — UNVERIFIED (downstream report unparseable)".
6. Read the fix report's regression-test seam evidence:
     - Tests > Regression test:  <test file path>
     - Tests > RED→GREEN:        <transition evidence>
   If the seam evidence is missing for a non-NO_INFRA / non-RUNNER_BROKEN
   status, treat the outcome as UNVERIFIED. Silence-as-evidence is forbidden.
7. Append a "## Fix Iteration N" block to .tl/tasks/TECH-###/result.md:

     ## Fix Iteration N — <ISO timestamp>
     Source: review.md (Blocker: A, Critical: B, Major: C)
     Delegated to: /nacl-tl-fix --uc TECH-### --from-review
     Fix Status: <Status: line value, verbatim from nacl-tl-fix report>
     Fix Headline: <header line from nacl-tl-fix report>
     Regression-test seam:
       - test file: <path or "n/a (NO_INFRA / RUNNER_BROKEN)">
       - RED→GREEN: <evidence string from fix report>
     Issues addressed:
       1. [BLOCKER] <title> @ <file:line> — <one-line outcome>
       2. [CRITICAL] <title> @ <file:line> — <one-line outcome>
       ...
     Issues NOT addressed (MINOR, deferred):
       - [MINOR] <title> @ <file:line>

8. Update status.json:
     - Status: PASS                        → status = "ready_for_review"
     - Status: BLOCKED + operator accept   → status = "ready_for_review"
                                             (record acceptance reason in
                                             blocked_accept_reason)
     - Status: BLOCKED (no acceptance)     → status = "in_progress"
     - Status: UNVERIFIED                  → status = "in_progress"
     - Status: NO_INFRA                    → status = "in_progress"
     - Status: RUNNER_BROKEN               → status = "in_progress"
     - Status: REGRESSION                  → status = "in_progress"
   For all non-PASS / non-accepted-BLOCKED outcomes, write:
     continue_failure_reason = "<Status: value> — <one-line>"

9. Do NOT auto-commit on non-PASS. /nacl-tl-fix already commits its
   own fix on PASS / accepted-BLOCKED (per its Step 6 commit gate); for
   any other status, surface the result to the operator and stop.

Continue: silence-as-evidence is forbidden

If the fix sub-agent's report does not contain a Status: line, or omits the regression-test seam (Tests > Regression test, Tests > RED→GREEN) for a status that requires it (anything other than NO_INFRA or RUNNER_BROKEN), this skill does NOT promote the task to ready_for_review. Silence is UNVERIFIED; require explicit evidence to advance.


Step 4: Create result.md

Create .tl/tasks/TECH-###/result.md documenting:

  • Summary of implementation
  • Workflow used (TDD or verification-based)
  • Files created/modified with line counts
  • Status headline and resolved status (PASS / UNVERIFIED / BLOCKED / NO_INFRA / RUNNER_BROKEN / REGRESSION)
  • Baseline diff (failures or state pre vs post the change)
  • Verification results (test results or infrastructure checks)
  • Commits made
  • Known issues (if any)
  • Ready for review checklist

Note: TECH tasks use result.md (not result-be.md or result-fe.md).

Step 5: Update Tracking

Update status.json for the task. Status transition is gated on the resolved A.5 / B.4 status:

Resolved statusstatus value
PASSready_for_review
BLOCKED (with explicit operator acceptance + recorded rationale)ready_for_review
BLOCKED (no acceptance)in_progress (blocked rationale recorded)
UNVERIFIEDin_progress
NO_INFRAin_progress
RUNNER_BROKENin_progress
REGRESSIONin_progress (return to A.4 / B.2)
{
  "id": "TECH-###",
  "type": "tech",
  "status": "ready_for_review",
  "wave": 0,
  "completed": "YYYY-MM-DDTHH:MM:SSZ"
}

For non-PASS / non-accepted-BLOCKED outcomes, also write failure_reason with the verbatim Status: value and a one-line summary.

Append to changelog.md:

## [YYYY-MM-DD HH:MM] DEV: TECH-### - Task Title
- Phase: Development
- Type: Infrastructure
- Status: [DEV COMPLETE | DEV APPLIED — UNVERIFIED | DEV APPLIED — BLOCKED | DEV APPLIED — NO_INFRA | DEV APPLIED — RUNNER_BROKEN | DEV INCOMPLETE — REGRESSION]
- Changes: N files, +X/-Y lines
- Verification: [TDD N tests passed | Infrastructure checks passed | UNVERIFIED — reason]

Test File Naming

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
27
Forks
4
Last commit
Sep 2026
Advanced
Item type
skill
Key
nacl-tl-dev
Source
github.com/itsalt/nacl