Saltearse al contenido

Quickstart

Esta página aún no está disponible en tu idioma.

This tutorial walks you through the core Contextia workflow: initializing a project, creating a spec, annotating your code, and validating that everything links together. By the end, you will have a working .contextia/ directory with a real spec, annotated code, and passing checks.

We will use a small Python project as the example, but Contextia works with any language.

Navigate to your project root and run:

Terminal window
contextia init

Contextia detects your project’s language and structure, then creates the .contextia/ directory:

Detected languages: python
Created .contextia/config.yaml
Created .contextia/system/identity.md
Created .contextia/system/specs/
Created .contextia/system/rationale/
Created .contextia/system/norms/
Created .contextia/work/tasks/
Initialized Contextia project in /home/user/my-project

The init command auto-detects your project’s languages by looking for telltale files (pyproject.toml, package.json, Cargo.toml, go.mod, etc.) and configures annotation parsing accordingly.

Let’s look at what was generated:

.contextia/config.yaml
version: "1.0"
project:
name: my-project
languages:
- python
paths:
source:
- src/
test:
- tests/
annotations:
prefix: "@"
comment_syntax:
python: "#"
output:
color: true
default_format: human

The identity file is a Markdown document that describes your project for both humans and AI agents:

.contextia/system/identity.md
---
type: identity
version: 1
---
# my-project
<!-- Describe your project: what it does, who it serves, key constraints -->

Specs are behavioral contracts — they define what your system should do. Let’s create one for a user authentication module:

Terminal window
contextia new spec --title "User Authentication"

This creates a new spec from the built-in template:

Created .contextia/system/specs/SPEC-001-user-authentication.md

Open the file and fill in the spec:

.contextia/system/specs/SPEC-001-user-authentication.md
---
type: spec
id: SPEC-001
title: User Authentication
status: draft
decisions:
- DEC-001
paths:
- src/auth/login.py
- src/auth/tokens.py
tags:
- auth
- security
---
# User Authentication
## Overview
The authentication module handles user login, token issuance, and session
validation. All endpoints require HTTPS. Passwords are never stored in
plaintext.
## Behavior
### Login
- Accept email and password via POST `/api/auth/login`
- Validate credentials against the user store
- On success, return a JWT access token (15 min expiry) and a refresh token (7 day expiry)
- On failure, return 401 with a generic error message (do not reveal whether the email exists)
### Token refresh
- Accept a valid refresh token via POST `/api/auth/refresh`
- Return a new access token
- If the refresh token is expired or revoked, return 401
### Logout
- Accept an access token via POST `/api/auth/logout`
- Add the token to the revocation list
- Return 204
## Constraints
- Passwords hashed with bcrypt, minimum cost factor 12
- JWT signed with RS256, keys rotated quarterly
- Rate limit: 5 failed login attempts per email per 15-minute window

Notice the frontmatter fields:

  • id: SPEC-001 — unique identifier, referenced by tasks and code annotations
  • status: draft — lifecycle state (draft, active, deprecated, superseded)
  • decisions — links to architectural decisions that constrain this spec
  • paths — source files that implement this spec (top-down traceability)
  • tags — for search and filtering

Now let’s connect the spec to your source code. Open a source file and add annotations using comments:

src/auth/login.py
from datetime import datetime, timedelta
from auth.tokens import create_access_token, create_refresh_token
from auth.users import verify_credentials
from auth.rate_limit import check_rate_limit, record_failure
# @spec SPEC-001
# @spec SPEC-001.login
async def login(email: str, password: str) -> dict:
"""Authenticate a user and return token pair."""
if not check_rate_limit(email):
raise RateLimitError("Too many login attempts")
user = await verify_credentials(email, password)
if user is None:
record_failure(email)
# @decision DEC-001 -- generic error, do not reveal email existence
raise AuthenticationError("Invalid credentials")
access_token = create_access_token(user.id, expires=timedelta(minutes=15))
refresh_token = create_refresh_token(user.id, expires=timedelta(days=7))
return {
"access_token": access_token,
"refresh_token": refresh_token,
}
# @spec SPEC-001.logout
async def logout(token: str) -> None:
"""Revoke an access token."""
await revoke_token(token)

The annotations create bottom-up links from code to specs:

  • @spec SPEC-001 — this function implements the User Authentication spec
  • @spec SPEC-001.login — specifically the login sub-behavior
  • @decision DEC-001 — this line is constrained by a specific architectural decision

These annotations complement the top-down links in the spec’s frontmatter (paths: [src/auth/login.py]). Together, they form bidirectional traceability between specs and code.

The check command validates the integrity of your context architecture. It verifies that links between artifacts are consistent, required fields are present, and annotations in code match their specs:

Terminal window
contextia check

If everything is correctly linked, you will see:

Checking .contextia/ integrity...
Specs: 1 found, 1 active
Decisions: 0 found (1 referenced but missing: DEC-001)
Norms: 0 found
Tasks: 0 found
Annotations: 3 found in 1 file
Warnings:
SPEC-001 references DEC-001 but no decision file exists
→ Create it with: contextia new decision --id DEC-001
Annotations validated:
✓ src/auth/login.py:9 @spec SPEC-001 (spec exists)
✓ src/auth/login.py:10 @spec SPEC-001.login (spec exists)
✓ src/auth/login.py:19 @decision DEC-001 (decision missing)
Result: 1 warning, 0 errors

The check found that our spec references DEC-001, but we have not created that decision file yet. Let’s fix that:

Terminal window
contextia new decision --id DEC-001 --title "Generic authentication errors"
.contextia/system/rationale/DEC-001-generic-authentication-errors.md
---
type: decision
id: DEC-001
title: Generic authentication errors
status: accepted
date: 2026-03-02
specs:
- SPEC-001
---
# Generic authentication errors
## Context
The login endpoint needs to communicate authentication failures to the client.
## Decision
Return a generic "Invalid credentials" message for all authentication failures,
regardless of whether the email exists in the system.
## Rationale
Revealing whether an email is registered enables account enumeration attacks.
A generic error message prevents attackers from distinguishing between
"email not found" and "wrong password" scenarios.
## Alternatives considered
- **Specific error messages**: Better UX but enables enumeration.
Rejected for security reasons.
- **Timing-equalized responses**: Add artificial delay to mask lookup timing.
Considered complementary, not a replacement for generic messages.

Run check again:

Terminal window
contextia check
Checking .contextia/ integrity...
Specs: 1 found, 1 active
Decisions: 1 found, 1 accepted
Norms: 0 found
Tasks: 0 found
Annotations: 3 found in 1 file
All annotations validated ✓
All links resolved ✓
Result: 0 warnings, 0 errors

The trace command shows full traceability for a file or directory — which specs govern it, which decisions constrain it, and which tasks have touched it:

Terminal window
contextia trace src/auth/
Tracing: src/auth/
src/auth/login.py
├── @spec SPEC-001 User Authentication
│ ├── @spec SPEC-001.login (sub-behavior: login)
│ └── @decision DEC-001 Generic authentication errors
└── @spec SPEC-001.logout (sub-behavior: logout)
src/auth/tokens.py
└── @spec SPEC-001 User Authentication (via paths in spec)
Coverage:
Files with annotations: 1 / 2 (50%)
Spec path coverage: 2 / 2 (100%)

Trace gives you a complete picture of how code, specs, and decisions relate. It works at file, directory, or individual spec level:

Terminal window
# Trace a single spec to see all its linked artifacts
contextia trace SPEC-001
# Trace with full depth to include norms and task history
contextia trace src/auth/ --depth full

With the MCP server configured (see Installation), here is what an AI agent experiences when it connects to your project:

  1. The MCP server starts and discovers your .contextia/ directory
  2. The agent receives the contextia://identity resource automatically — your project’s identity file
  3. The agent receives the contextia://index resource — a navigation map of all specs, decisions, norms, and tasks

When the agent is assigned a task, it calls load_context to get everything it needs:

Agent calls: load_context(task_id="TASK-042")
Response includes:
- Task TASK-042 full content
- SPEC-001 (referenced by task)
- DEC-001 (referenced by SPEC-001)
- Applicable norms (matched by tag)
- Previous session logs (if any)

The agent works with full knowledge of the relevant specs and constraints. It does not need to search, guess, or ask you to paste context into the chat.

You now have a working Contextia project with:

  • A configured .contextia/ directory
  • A behavioral spec with frontmatter links
  • Code annotations creating bidirectional traceability
  • Passing integrity checks

From here, you can:

  • Create a task with contextia new task to assign work that references your specs
  • Add norms with contextia new norm to codify your team’s coding conventions
  • Set up the MCP server to let AI agents access your context architecture directly
  • Add contextia check to your CI pipeline to prevent broken links from being merged

For a deeper understanding of each artifact type and its schema, see the reference documentation.