Skip to content

Agent injection

tickety-ai reads .tickety/devcontract.json at every session start and injects it as the first block of Claude's system prompt — before any steering .md files. This is Phase 1 of the DevContract model: contract acknowledgement before any work begins.

How it works

When you open a session in tickety-ai, the extension calls loadSteeringFiles(cwd). This function:

  1. Looks for .tickety/devcontract.json.
  2. If found, parses and passes it to renderContract(), which formats it as a compact, structured text block.
  3. The contract block is placed first — parts.unshift(contractBlock) — so it is always the first content in the system prompt.
  4. Steering .md files from .tickety/steering/ follow.
  5. If no contract file exists, the session continues with steering files only. No error is raised.

The rendered contract block

renderContract() converts the JSON object into a compact, plain-text format optimised for LLM consumption. An example for the ticketyboo.dev free-tier contract:

== ACTIVE DEVCONTRACT (v1.0) ==
Project: ticketyboo.dev | Client: fenderfonic | Contractor: claude-code

STACK: python 3.12 | Runtime: aws_lambda | Region: eu-north-1
FORBIDDEN SERVICES: ec2, fargate, lightsail, rds

ARCHITECTURE:
  Required patterns: single_table_dynamodb, handler_delegates_to_domain
  Forbidden patterns: fat_handler, orm_layer

COST ENVELOPE: aws_free_tier
  Forbidden resources: nat_gateway, rds, secrets_manager, kms_cmk, elastic_ip
  Approved exceptions: route53_hosted_zone

SECURITY:
  Auth: cognito_jwt
  Secrets: ssm_parameter_store ONLY
  Never store secrets in: env_vars, source_code, config_files
  PII handling: redact_before_llm
  OWASP compliance: REQUIRED
  Production deploy: REQUIRES HUMAN APPROVAL

QUALITY:
  Type hints: REQUIRED on all functions
  Docstrings: public_only functions
  Coverage minimum: 80%
  Logging: module_logger_only — no print()
  Forbidden: print_statements, bare_except, mutable_defaults

COMPLIANCE: GDPR
  Data deletion: hard_delete_only — never soft-delete
  PII: must be classified before any LLM processing
  Data residency: eu_only

AUDIT: evidence_required | signed_receipt | pr_comment_required

DEFINITION OF DONE:
  ✓ tests_pass | ✓ coverage_met | ✓ no_contract_violations | ✓ evidence_generated | ✓ security_scan_pass | ✓ pr_comment_posted
  Scan gates: secret:critical (blocking), sast:high (blocking), dependency:critical (blocking)

== END CONTRACT — you are operating under these terms ==

What Claude does with it

Because the contract block is the first content in the system prompt, Claude reads it before any task description, before any steering files, and before any user message. The expected behaviour is:

  • Phase 1 — Acknowledgement: Claude confirms it has read the contract terms before beginning any work.
  • Phase 2 — Active consultation: Before any material decision (choosing a cloud service, selecting a pattern, handling a secret), Claude checks the relevant clause and states which clause applies to the decision.
  • Phase 3 — Delivery confirmation: When work is complete, Claude confirms which definition_of_done criteria have been met and which remain outstanding.

Implementation reference

The injection is implemented in two files in the tickety-ai extension:

FileResponsibility
src/core/steering/renderContract.ts Converts a parsed devcontract.json object to a formatted steering block string. Handles all 8 clause families. Gracefully omits absent optional clauses.
src/core/steering/inject.ts loadSteeringFiles(cwd) — reads the contract, calls renderContract(), prepends to parts[], then appends steering .md files.

System prompt order

The full system prompt assembly order at session start:

  1. DevContract block — rendered from .tickety/devcontract.json (if present)
  2. Steering files — all .md files from .tickety/steering/, sorted alphabetically
  3. Mode system prompt — the role definition for the current mode (Code, Architect, Debug, etc.)
  4. Tool definitions
  5. Conversation history

The contract is always first. This ensures it is never buried below mode instructions or previous conversation context.

Failure behaviour

If devcontract.json cannot be read (file missing, permission denied) or cannot be parsed (malformed JSON), loadSteeringFiles() silently continues without the contract block. No error is surfaced to the user.

To validate your contract before a session, use load_contract() from contract_schema.py in a pre-session check or CI step.