CodeMender Skills & Hooks for Antigravity

1. Introduction

In this codelab, you will configure an AI coding agent (Antigravity) so that security is part of its normal development loop rather than a separate review step. You will install a set of agent skills that walk the agent through a Plan → Red → Green → Refactor cycle, and a PreToolUse hook that intercepts git push, scans the changed files with CodeMender, and hands any findings back to the agent with instructions to fix them test-first.

The skills and hook come from the open-source Secure TDD Agent Framework. You will install them into the same ~/codemender-lab workspace you built in CodeMender CLI Basics.

What you will learn

  • How Antigravity discovers workspace rules, skills, and hooks under .agents/.
  • What the six Secure TDD skills do and which phase of the loop each one owns.
  • How a PreToolUse hook receives the agent's tool call on stdin and returns an allow/deny decision.
  • How the security gate hook (security_gate_hook.sh) runs cm find, classifies findings by severity, tracks fix attempts, and escalates with cm verify.
  • How to verify the whole hook pipeline offline with mock scanners before pointing it at the real cm.

Prerequisites

  • Completion of CodeMender CLI Basics. This lab continues in the ~/codemender-lab directory and reuses its sample_app/, CONTEXT.md, git history, and ~/.codemender/config.yaml.
  • Antigravity installed, with the ability to open a local folder as a workspace.
  • git, jq, and bash installed. The hook scripts are plain bash and run on macOS's stock bash 3.2 as well as newer versions.
  • The Python virtual environment from CodeMender CLI Basics (~/codemender-lab/.venv) with Flask installed.
  • Basic shell scripting knowledge.

2. Workspace Setup

Step 1: Return to the lab directory

All commands in this lab run from ~/codemender-lab with the virtual environment active:

cd ~/codemender-lab && source .venv/bin/activate

Confirm that the workspace from the previous lab is intact and that your working tree is clean:

ls sample_app/data_service.py CONTEXT.md .gitignore
git status --short

git status --short should print nothing. If it lists files, commit them before continuing.

Step 2: Name the branch main

The security gate diffs your working tree against origin/main to decide which files to scan. If that ref does not exist it falls back to HEAD~1, which only covers the most recent commit. Make sure your branch is called main:

git branch -M main

Step 3: Add a test suite entry point

The Secure TDD loop asks the agent to run python3 -m unittest discover -s tests after every fix, so the workspace needs a tests/ directory. Start with one characterization test so the suite has something real to run:

mkdir -p tests && touch tests/__init__.py
cat << 'EOF' > tests/test_data_service.py
import unittest

from sample_app.data_service import hash_password


class HashPasswordTests(unittest.TestCase):
    def test_returns_hex_digest(self):
        digest = hash_password("hunter2")
        self.assertIsInstance(digest, str)
        int(digest, 16)  # raises ValueError if not hexadecimal


if __name__ == "__main__":
    unittest.main()
EOF
python3 -m unittest discover -s tests

You should see Ran 1 test and OK.

Step 4: Extend .gitignore and commit

Add the runtime files this lab produces to .gitignore, then commit the baseline:

printf '.security-gate/\nusers.db\n*.bak\n' >> .gitignore
git add -A && git commit -m "Add test suite entry point for Secure TDD"

3. Installing the Framework Files

The skills, rule, hook, and offline test harness all live under a single .agents/ directory. Rather than typing roughly 800 lines of bash by hand, clone the framework and copy that directory into your workspace:

git clone --depth 1 https://github.com/h3xar0n/secure-tdd-agent-framework.git /tmp/secure-tdd
cp -R /tmp/secure-tdd/.agents ./.agents
rm -rf /tmp/secure-tdd

Confirm the layout:

find .agents -type f | sort
.agents/hooks.json
.agents/lib/README.md
.agents/lib/engine_codemender.sh
.agents/lib/engine_semgrep.sh
.agents/lib/gate_common.sh
.agents/rules/secure_tdd_workflow.md
.agents/security_gate_hook.sh
.agents/skills/defensive-developer/SKILL.md
.agents/skills/history-context-seeder/SKILL.md
.agents/skills/local-refactor-scanner/SKILL.md
.agents/skills/security-test-writer/SKILL.md
.agents/skills/skill-evolution-updater/SKILL.md
.agents/skills/threat-model-assessor/SKILL.md
.agents/tests/mocks/cm
.agents/tests/mocks/semgrep
.agents/tests/run_tests.sh

Make sure the hook entry point is executable:

chmod +x .agents/security_gate_hook.sh
ls -l .agents/security_gate_hook.sh

The rest of this lab walks through what you just installed, one piece at a time.

4. The Always-On Workflow Rule

Skills are loaded on demand, when the agent decides a skill's description matches the task. Something has to tell the agent to reach for them in the right order. That is the job of .agents/rules/secure_tdd_workflow.md. Its frontmatter sets trigger: always_on, so the rule is injected into every turn:

---
trigger: always_on
---

# Test-Driven Development with Integrated Security (Secure TDD) Workflow Rule

You MUST strictly follow this 4-phase cyclical workflow for all feature implementations, refactors, and bug fixes:

1. **Phase A (Plan, Scope & Threat Model)**:
   - Ingest `CONTEXT.md` to review established project conventions, approved helpers, and trust zones.
   - Decompose feature requirements, user stories, and acceptance criteria.
   - Invoke the **Threat Model Assessor Skill** to perform a STRIDE evaluation and generate/update `threat_model.md`.

2. **Phase B (Functional & Security Test-First - RED)**:
   - Invoke the **Security Test Writer Skill**.
   - Author unit and integration tests asserting functional behavior (happy paths, business logic), edge cases, AND security boundaries (rejecting invalid inputs, unauthenticated requests, unauthorized role access).
   - Execute the tests and confirm they FAIL for the expected assertion reason (RED).

3. **Phase C (Feature Implementation & Defensive Code - GREEN)**:
   - Invoke the **Defensive Developer Skill**.
   - Author clean, modular production code strictly required to satisfy the functional tests and security assertions.
   - Apply input validation allow-lists, parameterized queries, and least-privilege payload returns.
   - Run the tests to confirm they are GREEN.

4. **Phase D (Refactor, Quality & Scan)**:
   - Invoke the **Local Refactor & Scanner Skill**.
   - Clean up code, eliminate duplication, and verify 100% passing test regressions.
   - Run fast deterministic checks (secrets, dependencies, local SAST).
   - Conduct a guided AI review to verify architectural boundaries and eliminate logic bypasses.
   - Ensure diffs remain small, surgical, and preserve baseline stability.

5. **Continuous Evolution**:
   - If a new pattern, helper function, or architectural convention was introduced, invoke the **Skill Evolution Updater Skill** to document the lesson into `CONTEXT.md` or the appropriate `SKILL.md`.

6. **Multi-Finding Remediation Protocol**:
   - When resolving multiple findings from a scan or security gate rejection, iterate sequentially one finding at a time:
     1. Author one discrete boundary test for the finding (RED).
     2. Implement the minimal defensive fix (GREEN).
     3. Verify local tests pass before moving to the next finding.
   - Avoid applying multi-finding changes in a single unverified edit. Run the full regression test suite only after all individual findings have passed their discrete TDD cycle.

The rule references CONTEXT.md, which you created in CodeMender CLI Basics. The same file that steered cm fix toward your parameterized-query convention now steers the agent's planning. Item 6 matters most for this lab: it is what the agent follows when the security gate rejects a push with several findings at once.

5. The Six Agent Skills

Each skill is a directory containing a SKILL.md with YAML frontmatter. Two fields are required:

  • name: a lowercase, hyphenated identifier.
  • description: what the skill does and when to use it. The agent reads only this field when deciding whether to load the full skill, so each description below also says what the skill is not for.

Skill

Phase

Purpose

threat-model-assessor

A: Plan

Scope the feature, run STRIDE, write threat_model.md.

security-test-writer

B: Red

Write functional and boundary tests that fail for the right reason.

defensive-developer

C: Green

Write the minimal code that turns the tests green, using safe patterns.

local-refactor-scanner

D: Refactor

Clean up, run the full suite, run local scanners, review the diff.

skill-evolution-updater

Continuous

Record new conventions in CONTEXT.md and SKILL.md files.

history-context-seeder

Onboarding

Mine git history to seed CONTEXT.md in an existing repository.

The full contents follow so you can see how the frontmatter and instructions fit together.

1. threat-model-assessor (Phase A)

.agents/skills/threat-model-assessor/SKILL.md:

---
name: threat-model-assessor
description: Plans feature architecture, functional requirements, and evaluates STRIDE security boundaries in Phase A Plan. Use when scoping new features or bug fixes, defining user stories and acceptance criteria, identifying trust boundaries, and generating or updating threat_model.md. Do not use for writing test assertions, implementing production code, or running local scanners.
---

# Planning, Requirements & Threat Model Assessor Skill (Phase A: Plan Phase)

## Overview
Decompose feature requirements, establish functional acceptance criteria, and map trust boundaries before any production code is authored. This skill pairs functional engineering scoping with STRIDE threat modeling at the planning stage, establishing the functional and security acceptance criteria consumed by downstream test writers.

## System Sequence
1. **Ingest Context**: Read `CONTEXT.md` to identify existing architecture, trust boundaries, approved libraries, and conventions.
2. **Decompose Requirements**:
   - Define user stories, input/output data contracts, and functional acceptance criteria.
   - Break complex tasks into bite-sized, testable implementation stages.
3. **Apply STRIDE Threat Modeling**:
   - **Spoofing**: Authentication boundaries, session validation, caller identity checks.
   - **Tampering**: Input payload validation, integrity checks, parameter tampering.
   - **Repudiation**: Audit logging of critical state transitions.
   - **Information Disclosure**: Restrict error responses, prevent stack trace leaks, mask PII/secrets.
   - **Denial of Service**: Resource limits, payload size constraints, timeout limits.
   - **Elevation of Privilege**: Role-Based Access Control (RBAC), caller authorization checks.
4. **Generate/Update `threat_model.md`**:
   - Store or update `threat_model.md` at the workspace root with both Functional & Security Acceptance Criteria.

## Target Output Artifact (`threat_model.md`)
```markdown
# Feature Plan & Threat Model: [Feature Name]

## 1. Functional Scope & Requirements
- **Goal**: [Description of feature or bug fix]
- **Deliverables**: [Endpoints, functions, or modules to create/modify]
- **Functional Acceptance Criteria**: [Expected behaviors and outputs]

## 2. Entry Points & Data Inputs
- Endpoint / Input: [Path / Name]
- Format & Constraints: [Schema / Type]

## 3. Trust Boundaries & Access Controls
- Authentication: [Required / Public]
- Authorization Role: [User / Admin]

## 4. STRIDE Threat Matrix & Security Acceptance Criteria
- [STRIDE Category]: [Threat Description] -> [Required Mitigation & Test Assertion]
```

2. security-test-writer (Phase B)

.agents/skills/security-test-writer/SKILL.md:

---
name: security-test-writer
description: Authors test-first unit and integration tests covering functional behavior, edge cases, and security boundaries in Phase B RED. Use when creating failing automated tests before writing production code, asserting HTTP status codes and contract responses, establishing boundary limits, or asserting that exploit payloads are rejected cleanly. Do not use for threat modeling during initial planning, writing production feature code, or running refactor sweeps.
---

# QA & Security Test Writer Skill (Phase B: RED Phase)

## Overview
Translate functional requirements and security criteria from `threat_model.md` and `CONTEXT.md` into executable test cases that fail initially (RED), asserting expected business logic, edge-case handling, and security boundaries before production code is authored.

## Three Verification Pillars
1. **Behavior-Driven Outcomes**:
   - Assert strictly on API/HTTP outcomes (status codes 200/302 for valid requests, 400/401/403 for invalid/unauthorized, expected JSON responses) rather than mocking internal private methods.
2. **Strict Test Isolation**:
   - Ensure test setup and teardown cleanly isolate state (e.g., transaction rollbacks, fresh test contexts) so state never bleeds between test runs.
3. **Integration Over Fragile Mocking**:
   - Utilize local test databases or real server contexts rather than fragile fake mocks to verify realistic functional and security behavior.

## Execution Sequence
1. **Consume Requirements & Threat Model**: Read the task scope, `threat_model.md`, and `CONTEXT.md` for functional requirements and security acceptance criteria.
2. **Author Test Cases**:
   - **Functional Happy Path**: Test validating standard user workflows and expected output payloads.
   - **Functional Edge Cases**: Test missing optional/required parameters, boundary limits, and unexpected data types.
   - **Authentication Boundary**: Assert requests without valid credentials return `401 Unauthorized`.
   - **Authorization Boundary**: Assert requests with insufficient role/scope return `403 Forbidden`.
   - **Input Validation**: Assert malformed, oversized, or un-whitelisted data returns `400 Bad Request`.
   - **Exploit Payloads**: Assert dangerous inputs (SQLi, path traversal `../../`, XSS) are rejected cleanly.
3. **Execute & Verify RED**:
   - Run the project's test command (e.g., `pytest`, `python3 -m unittest discover -s tests`).
   - **Requirement**: Confirm the tests fail due to the expected missing feature logic/boundary assertion and not due to a syntax or import error.
4. **Multi-Finding Handling**:
   - When remediating multiple scanner findings, write and verify one boundary test for one finding at a time before proceeding to defensive implementation.

3. defensive-developer (Phase C)

.agents/skills/defensive-developer/SKILL.md:

---
name: defensive-developer
description: Implements clean, maintainable production code to deliver features and satisfy functional and security test assertions in Phase C GREEN. Use when writing minimal, modular production code to turn failing RED tests GREEN, applying input validation allow-lists, enforcing explicit caller authorization, and using parameterized sinks and least-privilege payloads. Do not use for authoring initial tests, performing initial threat modeling, or running post-implementation security scans.
---

# Feature Implementation & Defensive Developer Skill (Phase C: GREEN Phase)

## Overview
Implement clean, modular production code that delivers the requested feature or bug fix and satisfies all functional, edge-case, and security assertions from Phase B while adhering to defensive design principles and project conventions in `CONTEXT.md`.

## Three Defensive Pillars
1. **Simple Input Validation**:
   - Enforce type, size, and strict allow-list validation on all incoming data.
   - Prefer structured parsing libraries (`pydantic`, `urllib.parse`) over complex regex which may be vulnerable to ReDoS.
2. **Explicit Authorization**:
   - Validate caller identity and match required permissions before invoking business logic.
3. **Least Privilege & Safe Operations**:
   - Parameterize all SQL/database queries.
   - Use canonical path checks (`os.path.realpath`) with prefix boundary validation.
   - Return only the minimal data payload required by the client.
   - Mask credentials, PII, and omit internal stack traces in error messages.

## Execution Sequence
1. **Inspect Failing Tests & Rules**: Review the functional requirements, failing tests from Phase B, and conventions in `CONTEXT.md`.
2. **Author Clean Production Code**:
   - Implement the business logic and algorithms required to satisfy the functional feature requirements.
   - Apply defensive patterns (e.g. `utils.security.resolve_safe_path`, parameterized SQL statements, `pydantic` schemas).
3. **Confirm GREEN State**:
   - Run the project test suite.
   - Verify that all functional and security tests pass cleanly without errors.
4. **Multi-Finding Handling**:
   - When remediating multiple scanner findings, apply the minimal fix for the current failing boundary test, confirm GREEN, then proceed to the next finding's test-fix cycle.

4. local-refactor-scanner (Phase D)

.agents/skills/local-refactor-scanner/SKILL.md:

---
name: local-refactor-scanner
description: Refactors code for quality and maintainability, executes full test suite regression passes, and runs local deterministic security and lint scans in Phase D REFACTOR. Use when cleaning up code structure and eliminating duplication after tests pass, running local linters and fast offline scanners for secrets or dependencies, executing full regression test suites, and performing guided code reviews. Do not use for implementing initial feature logic, writing failing test-first suites, or modifying architectural threat models.
---

# Code Refactoring, Quality & Local Scanner Skill (Phase D: REFACTOR Phase)

## Overview
Refactor implementation for clean code structure, modularity, and maintainability while ensuring 100% passing test regressions and blocking pattern-based security flaws locally prior to commit.

## Verification Guardrails
1. **Code Quality & Refactoring**:
   - Clean up boilerplate, eliminate dead code, and centralize common utilities.
   - Improve variable naming, modularity, and type annotations without altering verified behavior.
2. **Deterministic Scans (Fast & Offline)**:
   - **Secrets**: Check diffs for plaintext credentials, tokens, or private keys.
   - **Dependencies**: Flag unpinned dependencies or known CVEs in new packages.
   - **Rules-Based SAST**: Run local SAST rules on modified files (`semgrep scan --config auto --json` or `cm find`).
3. **Guided AI Review**:
   - Audit architecture and design issues that static tools miss.
   - Review business logic and edge cases for bypasses or regression risks.
4. **Small Diffs & Regression QA**:
   - Run the complete project test suite to verify zero regressions across existing and new tests.
   - Ensure the diff contains only surgical changes directly related to the task scope.

## Execution Sequence
1. Review the git diff of modified files (`git diff`).
2. Refactor code for clarity, maintainability, and helper reuse.
3. Run local linters and security scanners on changed files.
4. Run the full test suite to guarantee 100% passing tests.
5. **Continuous Evolution**: Capture new conventions in `CONTEXT.md` and suggest/apply updates to `SKILL.md` instructions via `skill-evolution-updater` to permanently prevent recurrence of issues.

5. skill-evolution-updater (Continuous Evolution)

.agents/skills/skill-evolution-updater/SKILL.md:

---
name: skill-evolution-updater
description: Extracts systemic conventions from resolved bugs, patterns, and refactors to update CONTEXT.md and agent skills for continuous evolution. Use when capturing durable coding rules, architectural conventions, or recurring fix patterns into CONTEXT.md after a task or bug fix, updating skill instructions to prevent recurrence of errors, and logging gate findings to findings-log.ndjson. Do not use for writing feature code, authoring unit tests, or running pre-push scanner pipelines.
---

# Skill & Conventions Evolution Updater (Continuous Evolution)

## Overview
Ensure the development team and agent fleet continuously learn from local fixes, architecture decisions, and refactoring patterns so that systemic quality and security standards are retained permanently.

## Continuous Feedback Mechanism
```
+-----------------------------------------------------------------+
|                    CONTINUOUS FEEDBACK LOOP                     |
|                                                                 |
|   1. Local Fix / Feature Verified (Refactor Phase)              |
|                               v                                 |
|   2. Systemic Lesson Extracted (Best practices & conventions)   |
|                               v                                 |
|   3. Feed Back to Shared Specs (Update SKILL.md/CONTEXT.md)     |
|                               v                                 |
|   4. Context Seeding (All future agents inherit rules upfront)  |
+-----------------------------------------------------------------+
```

## Execution Sequence
1. **Analyze Remediation Diff**: Review the code change or bug fix just completed.
2. **Extract the Systemic Rule**:
   - Formulate an actionable, project-specific rule.
   - Example: *"When implementing redirects, always use `utils.security.safe_redirect()` with allow-listed domains."*
   - Example: *"All JSON endpoints must validate request body using Pydantic schemas."*
3. **Update Shared Specifications**:
   - **Update `CONTEXT.md`**: Append the rule under `## 4. Continuous Evolution: Auto-Evolved Conventions`.
   - **Update Skills (if applicable)**: If a general coding anti-pattern or QA procedure was refined, update the relevant `SKILL.md`.
4. **Persist Insight**: Append the raw structured event to `.security-gate/findings-log.ndjson` for audit traceability.

6. history-context-seeder (Onboarding)

.agents/skills/history-context-seeder/SKILL.md:

---
name: history-context-seeder
description: Analyzes repository Git history for past bug fixes, architectural conventions, and security patterns to seed CONTEXT.md on onboarding. Use when first adopting the framework in an existing repository, mining historical commits and bug fixes for recurring risk areas, or populating the initial CONTEXT.md baseline with established conventions and helpers. Do not use for routine feature development, authoring test suites, or running the inner TDD loop on active tasks.
---

# History & Architectural Context Seeder Skill (Repository Onboarding)

## Overview
Analyzes the repository's Git history and past fix commits to extract recurring bug patterns, architectural conventions, and security patterns, seeding `CONTEXT.md` during initial repository onboarding.

## Execution Sequence
1. **Analyze Git Log**:
   - Inspect commits touching bug fixes, refactors, and sensitive modules:
     `git log --grep="fix\|bug\|refactor\|vuln\|security\|patch" -n 50 --oneline`
2. **Extract Historical Lessons**:
   - Identify which files and modules have historically been prone to bugs or regressions.
   - Extract past patterns and architectural conventions established by maintainers.
3. **Seed `CONTEXT.md`**:
   - Populate `CONTEXT.md` with known architectural risk areas, sensitive directories, approved helpers, and custom project conventions.

You will not use this skill in the labs because CONTEXT.md already exists, but it is the one to reach for when you bring the framework to a repository that has years of history and no written conventions.

6. Configuring the Antigravity Hook

.agents/hooks.json tells Antigravity to run the security gate before any terminal command the agent executes:

{
  "security-gate": {
    "PreToolUse": [
      {
        "matcher": "run_command|.*:run_command|run_shell_command|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'if [ -x ./security_gate_hook.sh ]; then exec ./security_gate_hook.sh; else exec ./.agents/security_gate_hook.sh; fi'",
            "timeout": 120
          }
        ]
      }
    ]
  }
}

A few details about this file explain the design of the script it launches:

  • matcher is a regex over tool names, not command text. PreToolUse fires before a tool runs, and the matcher decides which tools. run_command is Antigravity's terminal tool; the other alternatives cover plugin-namespaced variants and other agent platforms that share these files. A matcher like git push* would never fire because no tool is named that. Filtering on the actual command happens inside the script.
  • The hook receives the tool call on stdin. Antigravity pipes a JSON payload such as {"toolCall": {"name": "run_command", "args": {"CommandLine": "git push origin main"}}, ...}. The script reads .toolCall.args.CommandLine and exits immediately with an allow decision for anything that is not a git push.
  • The working directory is the directory containing hooks.json, so the hook starts inside .agents/. The bash -c 'if [ -x ./security_gate_hook.sh ] ...' wrapper handles both that case and being launched from the repository root. The script then cds to git rev-parse --show-toplevel before doing any work.
  • The script answers on stdout with JSON. {"decision": "allow"} lets the original command run. {"decision": "deny", "reason": "..."} blocks it and shows the reason to the agent. The framework also emits an allow_tool boolean for compatibility with older hook contracts.
  • Hooks run synchronously and block the agent loop until they finish or hit timeout (in seconds; the default is 30 if omitted).

The -i.bak form works with both GNU and BSD (macOS) sed:

sed -i.bak 's/"timeout": 120/"timeout": 900/' .agents/hooks.json && rm .agents/hooks.json.bak

7. How the Security Gate Hook Works

security_gate_hook.sh is a thin entry point that sources three modules from .agents/lib/:

Module

Role

gate_common.sh

Configuration defaults, allow/deny output, severity ranking, the NDJSON audit log, attempt counting, commit and CONTEXT.md helpers.

engine_semgrep.sh

Stage 1. Optional deterministic scan with Semgrep. Skipped if semgrep is not on PATH.

engine_codemender.sh

Stage 2. Semantic scan with cm find, classification, attempt tracking, and cm verify escalation.

Step 1: Decide whether this is a push

The entry point extracts the command from the stdin payload and tests it against a regex that recognizes git push in its common forms (git -C /repo push, cd x && git push, sudo git push) while ignoring quoted text such as git commit -m "before git push". Anything that is not a push is allowed immediately:

CMD_TO_CHECK=$(printf '%s\n' "$STDIN_INPUT" | jq -r '
  .toolCall?.args?.CommandLine? //
  .toolCall?.args?.command? //
  .tool_input?.command? //
  .CommandLine? //
  .command? //
  empty
')
...
if ! is_git_push_command "$CMD_TO_CHECK"; then
  allow
fi

Step 2: Choose the scanners

SECURITY_GATE_SCANNER selects the pipeline. The default, auto, runs whichever of Semgrep and CodeMender are installed, in that order:

case "$SCANNER" in
  codemender|cm) run_codemender_gate false ;;
  semgrep)       run_semgrep_gate false ;;
  auto|pipeline|"")
    command -v semgrep >/dev/null && run_semgrep_gate true
    command -v cm      >/dev/null && run_codemender_gate true
    allow ;;
esac

When Stage 1 finds blocking issues in pipeline mode it does not deny on its own; it writes them to a temp file that Stage 2 picks up, so CodeMender gets the final say.

Step 3: The CodeMender stage

run_codemender_gate in engine_codemender.sh does the following, in order:

  1. Find changed files with git diff --name-only origin/main (falling back to HEAD~1). No changes means allow.
  2. Scan each file with cm find "$file" -y --bypass-warning, then pull everything back with cm report --format json. If cm report fails or returns invalid JSON, that is a scan error, not a clean result.
  3. Filter to findings whose status is OPEN or REOPENED and whose file_path ends with one of the changed files. Findings you already fixed or dismissed in CodeMender CLI Basics are ignored.
  4. Classify each finding. Severity at or above SECURITY_GATE_BLOCK_SEVERITY (default HIGH) is blocking; anything lower is advisory, logged, and printed, but does not stop the push.
  5. Allow if nothing blocks. If a finding that blocked a previous push is now gone, the gate logs it as FIXED, appends a convention to CONTEXT.md under ## 4. Continuous Evolution, and commits that change.
  6. Count attempts per blocking finding by reading its own audit log. Each denial is one attempt. On attempts 1 through SECURITY_GATE_MAX_RETRIES (default 3), the gate logs DENIED_TO_AGENT and adds the finding to a rejection message.
  7. Escalate after the budget is spent. On the fourth attempt for the same finding, the gate runs cm verify. If the finding is not exploitable (exit code 1 or status DISMISSED), it is downgraded to advisory. If it is confirmed, or cm verify crashes, the gate logs BLOCKED and denies with a request for human review.
  8. Deny with instructions. If any findings remain actionable, the gate returns this reason to the agent:
Security Gate blocked push (1 unresolved finding(s)).

Action Required: Execute the Secure TDD Loop sequentially for each finding:
For each finding below (one at a time):
  1. Invoke 'security-test-writer' to author one failing boundary test in tests/ (assert RED).
  2. Invoke 'defensive-developer' to apply the minimal defensive fix (assert GREEN).
  3. Run the local test to confirm it passes before moving to the next finding.
Once all findings are resolved, run the full regression test suite (python3 -m unittest discover -s tests) and retry 'git push'.

Open Findings:
- [80bdddd6-...] (CRITICAL) in /home/you/codemender-lab/sample_app/data_service.py (Attempt 1/3): OS Command Injection in ping_host endpoint

This is the hand-off between hook and skills. The hook does not call cm fix. It names the skills the agent should use, the agent does the test-first fix, and the next git push re-runs the gate.

Configuration reference

All settings are environment variables with defaults set in gate_common.sh:

Variable

Default

Effect

SECURITY_GATE_SCANNER

auto

auto, codemender (or cm), or semgrep.

SECURITY_GATE_BLOCK_SEVERITY

HIGH

Lowest severity that blocks. CRITICAL, HIGH, MEDIUM, or LOW.

SECURITY_GATE_MAX_RETRIES

3

Denials per finding before cm verify is consulted.

SECURITY_GATE_ALLOW_ON_ERROR

false

true lets a push through when a scanner fails to run, tagging the commit unverified-scan-.

SECURITY_GATE_TEST_CMD

python3 -m unittest discover -s tests

Test command quoted in rejection prompts and commit messages.

SECURITY_GATE_EVOLVE_CONTEXT

true

Append verified conventions to CONTEXT.md.

SECURITY_GATE_LOG

.security-gate/findings-log.ndjson

Append-only audit log.

SECURITY_GATE_NOTIFY_CMD

(empty)

Optional command that receives each gate event as JSON on stdin.

8. Verifying the Hook Offline

Before the gate ever touches the real cm, confirm it behaves correctly with mocks. The framework ships a test harness with fake cm and semgrep binaries that cover allow, advisory, deny, error, and escalation paths:

bash .agents/tests/run_tests.sh

The run takes a few seconds and ends with:

-- test_pipeline_tools_missing_passes_smoothly
-- test_skills_frontmatter_valid
60 passed, 0 failed

The last test also validates the frontmatter of every skill under .agents/skills/, so this is the command to re-run after editing a SKILL.md.

Next, simulate what Antigravity sends for a command that is not a push. The script should answer allow without touching any scanner:

echo '{"toolCall":{"name":"run_command","args":{"CommandLine":"git status"}}}' \
  | bash .agents/security_gate_hook.sh
{"allow_tool": true, "decision": "allow"}

Now simulate a push with no local changes against origin/main. Because there is no remote yet, the gate falls back to HEAD~1 and scans the files from your last commit. To keep this step offline, point it at the mock cm and semgrep:

echo '{"toolCall":{"name":"run_command","args":{"CommandLine":"git push origin main"}}}' \
  | PATH="$PWD/.agents/tests/mocks:$PATH" bash .agents/security_gate_hook.sh
Stage 1: Running Deterministic AST Scan (semgrep) on: sample_app/data_service.py ...
Deterministic scan clean. No AST vulnerabilities found.
Stage 2: Running Semantic Analysis & Verification (CodeMender)...
No blocking vulnerabilities detected. Code verified clean.
{"allow_tool": true, "decision": "allow"}

Both stages ran because the mock directory contains a fake semgrep as well as a fake cm. Progress messages go to stderr and only the JSON decision goes to stdout, which is what lets Antigravity parse the result.

Finally, commit the framework files so they travel with the repository:

git add -A && git commit -m "Add Secure TDD skills, rule, and security gate hook"

9. Opening the Workspace in Antigravity

Open ~/codemender-lab as a folder in Antigravity. Once loaded, the agent has:

  • The secure_tdd_workflow rule in every turn.
  • The six skills available on demand.
  • The security-gate hook registered on run_command.

A quick way to confirm the skills are visible is to ask the agent, in a new conversation, "Which workspace skills do you have available, and what does each one do?" It should list the six by name.

Permissions

The hook itself is launched by Antigravity, not by the agent, so it does not go through the tool-permission prompts. The agent's own commands do. During the next codelab, expect approval prompts for the test command, git operations, and any cm command the agent decides to run directly. Approve them when asked; if Antigravity offers to remember the decision for a command prefix, accepting that avoids re-prompts across the loop.

What happens on git push

  1. The agent calls its terminal tool with git push origin main.
  2. Antigravity matches run_command against hooks.json and runs security_gate_hook.sh with the tool call on stdin.
  3. The script recognizes a push, finds changed files, scans them with cm find, and reads cm report.
  4. If nothing blocks, it prints {"decision": "allow"} and the push proceeds.
  5. If findings block, it prints {"decision": "deny", "reason": "..."}. The push does not run, the agent sees the reason, and the always-on rule plus the named skills tell it what to do next: one failing test, one minimal fix, re-run the suite, push again.

Congratulations! You have completed the CodeMender Skills & Hooks for Antigravity codelab. In the next codelab you will give the agent a feature request and watch this loop run end to end, from threat model to a push that passes the gate.