Skip to content

Getting started

Try it in 5 minutes — no API key

One command starts a fully seeded English demo (sample contract + code repo + past work items). No LLM key, no JVM, no Postgres — the decision path is fully deterministic:

git clone https://github.com/yasinyaman/etki.git && cd etki
docker compose -f docker-compose.demo.yml up --build

Open http://localhost:8000, log in as demo / demo (hard-coded for local evaluation only), open the Meridian CRM (demo) project → Triage, and try:

  • "We need SAML single sign-on with our corporate identity provider"out of scope, citing the explicit exclusion (Clause 7.1), with the effort such a CR would take — estimated from similar past tickets.
  • "Add a date filter to the monthly standard report"in scope (Clause 4.2.1), impacted modules, and an effort range by analogy.

Local development setup

Requirements: Python 3.12+ and uv.

uv sync --dev                                   # venv + dependencies (editable install)
cp .env.example .env                            # settings (LLM optional)
uv run python -m etki.persistence create-user   # first admin user (or ETKI_ADMIN_*)
uv run uvicorn etki.api.app:app --reload   # http://localhost:8000  (API docs: /docs)

Only the first admin user needs the CLI/env bootstrap — after that, manage users (roles, per-user project grants, password resets) from Settings → Users in the UI. Roles: pmo approves and administers, engineer runs triage/analysis, viewer is read-only.

Common commands:

uv run pytest                                   # all tests (no Joern/JVM; fakes/AST)
uv run ruff check . && uv run mypy etki    # lint + type check
uv run python -m eval.runner                    # CI gate: retrieval + decision back-test
uv run python -m eval.runner --dataset my.json  # benchmark YOUR labeled cases (--llm to score a model)
uv run python -m etki.indexing             # rebuild the index (live Joern; AST alternative)
uv run python -m etki.wiki search "SSO"    # decision wiki: search|show|rebuild (see Decision memory)
uv run python -m etki.mcp_server           # MCP server (see the MCP page)
docker compose up -d --build                    # app + Postgres (JVM-free container)

Enabling the LLM (optional)

With no API key the system runs deterministically/heuristically. The easiest way to enable the LLM seam (semantic fallback matching, pre-analysis prose, the agent) is from the UI: Settings → AI Assistant (pmo-only) — pick off / Anthropic / OpenAI-compatible, paste the key or endpoint, and hit Test connection. Values saved there are stored in .etki/llm.json (owner-readable only, git-ignored) and take precedence over env vars; changes apply on the next request, no restart. For production prefer env/.env:

ETKI_LLM_PROVIDER=anthropic
ETKI_ANTHROPIC_API_KEY=sk-ant-...

Fully air-gapped mode

The data Etki handles — client contracts, code, effort history — is exactly the kind that can't leave your network. Every layer has a local option, including the LLM (one OpenAI-compatible adapter covers Ollama, vLLM, LM Studio, llama.cpp server):

ETKI_LLM_BASE_URL=http://localhost:11434/v1   # Ollama endpoint (enables the local provider)
ETKI_LLM_MODEL=qwen2.5:3b                     # any model your server hosts

Local LLM + ast code engine + SQLite = zero external dependencies (the UI vendors its own assets — no CDN). With no LLM configured at all, triage is fully deterministic and reproducible.