Skip to content

Repository files navigation

titan-tyr

A graph-shaped REST API for parts and the interface contracts between them. Versioned markdown nodes and edges, all in Postgres.

titan-tyr is a small FastAPI service that records:

  • Parts — typed nodes in the graph. Each part has a subtype discriminator: software (a codebase / deployable boundary) or container (a running instance of an image).
  • Contracts — directed edges between two parts describing how one talks to the other. Each contract has a subtype: interaction (protocol/schema-level — env-agnostic) or binding (deployment address bound from a container to a software part — env-specific).

Both nodes and edges carry a versioned markdown body. The latest version is what reads return. Contracts additionally support proposals (and RC iterations of them) so a change can be drafted, revised, and accepted as the new active version without losing history.

            ┌──────────────────────────────────────────────────┐
            │                  titan-tyr API                   │
            │                                                  │
   part ──▶│ POST /parts           GET  /parts/{name}         │
contract ──▶│ POST /contracts       GET  /contracts/{id}       │
proposal ──▶│ POST /…/proposals     POST /…/{ver}/accept       │
            │                                                  │
            └─────────────────────────┬────────────────────────┘
                                      │
                                  PostgreSQL
                         (parts, contracts, *_versions)

Features

  • FastAPI + async SQLAlchemy + asyncpg. Auto-generated OpenAPI at /docs and /redoc.
  • Caller-supplied semver (MAJOR.MINOR.PATCH) on every write, validated for format and strict-greater-than-latest. The server refuses to interpret what a bump means — only the caller knows.
  • RC pre-release support (1.3.0-rc1, 1.3.0-rc2, …) on contract and template proposals, with full history preserved on acceptance.
  • Templates are versioned and proposable too. The software, container, interaction, and binding markdown templates served by the API live in Postgres alongside everything else, mutated through the same propose/accept flow.
  • First-class migrations. Alembic with autogenerate, a MetaData naming convention so diffs stay reproducible, and a CI policy of running alembic check against the model.
  • Test suite (95% coverage). Pytest + httpx + a throwaway Postgres via testcontainers; an env-var override is supported for shared dev instances.

Quickstart

python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[test]"

# Postgres for local dev
docker run --rm -d --name titan-tyr-pg -p 5432:5432 \
  -e POSTGRES_USER=titan -e POSTGRES_PASSWORD=titan -e POSTGRES_DB=titan_tyr \
  postgres:16-alpine

DATABASE_URL='postgresql+asyncpg://titan:titan@localhost:5432/titan_tyr' \
  alembic upgrade head

DATABASE_URL='postgresql+asyncpg://titan:titan@localhost:5432/titan_tyr' \
  uvicorn src.main:app --reload --port 8000
# Smoke test (no auth required — the /health endpoint is the orchestrator probe)
curl http://localhost:8000/health
# → {"status":"ok","version":"0.10.0","db":"reachable"}

# Sanity check on the auth path
curl -H 'Authorization: Bearer sysmlv2' http://localhost:8000/templates/software

Run from Docker

docker build -t titan-tyr:0.10.0 .

The image runs as a non-root app user, exposes port 8000, and bundles both uvicorn (default CMD) and alembic (override CMD to use it). Per DESIGN.md, migrations run as a separate step before the API container starts:

# 1. Apply migrations (one-shot)
docker run --rm \
  -e DATABASE_URL='postgresql+asyncpg://titan:titan@host.docker.internal:5432/titan_tyr' \
  titan-tyr:0.10.0 alembic upgrade head

# 2. Serve the API
docker run --rm -p 8000:8000 \
  -e DATABASE_URL='postgresql+asyncpg://titan:titan@host.docker.internal:5432/titan_tyr' \
  titan-tyr:0.10.0

(In Compose / Kubernetes, the migrate step is a depends_on job or an init container; the API container only starts once it exits 0.)

Authentication

Placeholder. A single shared bearer token (sysmlv2) gates every endpoint. Real per-caller auth is a deferred capability — see the Authentication section in DESIGN.md.

Authorization: Bearer sysmlv2

Configuration

Env var Required Description
DATABASE_URL yes Async DSN, e.g. postgresql+asyncpg://user:pw@host:5432/titan_tyr
CORS_ALLOWED_ORIGINS no Comma-separated literal origins replacing the default CORS allow-list. See docs/api.md § CORS.
CORS_ALLOW_ANY_ORIGIN no true opens CORS to any origin (*). Opt-in only. Takes precedence over CORS_ALLOWED_ORIGINS.

Run the tests

pytest

Spins up a Postgres in Docker via testcontainers, recreates the schema per test, asserts on every endpoint behaviour and on the semver module directly. To use an existing Postgres instead, set TEST_DATABASE_URL.

Project layout

src/                FastAPI app, ORM models, schemas, routers, semver
alembic/            Migrations (0001 = schema, 0002 = templates + seed, 0005 = software→part + subtype)
tests/              Pytest + testcontainers
docs/               getting-started, api reference (also see DESIGN.md)

Documentation

  • docs/getting-started.md — running it locally, running the tests, layout overview.
  • docs/api.md — endpoint reference with curl examples.
  • DESIGN.md — full design rationale: data model, schema, versioning rules, migration policy, open questions.
  • AGENTS.md — operating rules for AI coding agents working in this repo.

Claude Code skills

The titan-tyr skill catalog ships as a Claude Code plugin. The canonical source lives under skills/ at the repo root, with the plugin manifest at .claude-plugin/plugin.json and the marketplace listing at .claude-plugin/marketplace.json.

One-line bootstrap (preferred — fully non-interactive):

bash <(curl -fsSL https://raw.githubusercontent.com/Westfall-io/titan-tyr/main/scripts/install.sh)

(Will eventually be served from https://watchervault.digitalforge.app/install.sh once the mimiron-side endpoint lands.)

Manual install (equivalent, if you'd rather see each step):

/plugin marketplace add Westfall-io/titan-tyr
/plugin install watchervault

The plugin is named watchervault (the catalog wraps the broader WatcherVault system, not just titan-tyr's surface — naming the plugin after the product rather than the repo leaves room for future additions without a confusing rename). Skills become namespaced as /watchervault:<skill-name> (e.g. /watchervault:register-part). Pin to a specific release with #watchervault-vX.Y.Z on the marketplace add command.

Working in this repo (titan-tyr itself), the skills live at skills/ but Claude Code's project-local auto-discovery looks at .claude/skills/ — which we no longer populate. To exercise the skills from a tyr-dev session, install the plugin from the local checkout:

/plugin marketplace add .
/plugin install watchervault

Once installed (either from local or from Westfall-io/titan-tyr), skills are addressable only as /watchervault:<skill-name> — the bare /<skill-name> form does not work post-plugin. Skills expect TITAN_TYR_URL (and a per-caller TITAN_TYR_TOKEN) in the environment.

Legacy install path (deprecated, still functional during the transition) is the /update-skills script, which git-pulls the catalog into a consumer's .claude/skills/ directory. Prefer the plugin install above for new consumers.

  • /register-part — walk through registering a part (software or container subtype) against a running titan-tyr. Branches on subtype and fetches the matching template.
  • /register-contract — register a new contract between two parts already in titan-tyr. Branches on subtype (interaction for protocol/schema agreements, binding for env-specific deployment bindings). Picks the owner and counterparty via ?match=, fetches the matching template, POSTs to /contracts.
  • /update-part — append a new version to a registered part. Detects template-version drift and helps migrate.
  • /learn-part — look up everything titan-tyr knows about a registered part (description, ticket-filing target, contracts). Read-only; returns structured JSON.
  • /find-part — resolve a colloquial label or partial name ("front end", "billing") to a canonical part slug via GET /parts?match=. Read-only.
  • /propose-template-change — draft and POST a proposal to update one of titan-tyr's templates (software, container, interaction, binding). Does not auto-accept.
  • /propose-contract-change — draft and POST a proposal to amend an existing interface contract. Helps pick the contract, opens the active body for in-place editing, shows a unified diff. Does not auto-accept.
  • /accept-template-proposal — promote an open template proposal to the new active version. Mutates what every caller sees.
  • /accept-contract-proposal — promote an open contract proposal to the new active version. Helps pick the contract (by id, by part name, or from a list), shows a unified diff vs the active body.

About

WatcherVault REST API — Git-backed contract file server with environment-aware indexing of Parts, Ports, Interfaces, and Connections

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages