Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ docker run -p 5200:5200 -v ./config.json:/app/config.json orchestration
| `backend/db/migrate.py` | Programmatic Alembic migration runner |
| `backend/db/models_metadata.py` | SQLAlchemy Table definitions for Alembic |
| `backend/migrations/` | Alembic migration versions |
| `backend/middleware/auth.py` | JWT auth dependencies (Bearer, admin, SSE token) |
| `backend/mcp/server.py` | FastMCP stdio server for Claude Code integration |
| `backend/mcp/config.example.json` | MCP server config template |
| `backend/middleware/auth.py` | JWT + API key auth dependencies (Bearer, admin, SSE token) |
| `backend/models/` | Pydantic schemas, status enums |
| `backend/routes/auth.py` | Register, login, refresh, me endpoints |
| `backend/routes/checkpoints.py` | Checkpoint list, get, resolve endpoints |
| `backend/routes/admin.py` | Admin-only user management, system stats |
| `backend/routes/analytics.py` | Admin-only analytics (cost, outcomes, efficiency) |
| `backend/routes/external.py` | External task execution (claim, submit, release) |
| `backend/routes/rag.py` | Read-only RAG database inspection endpoints |
| `backend/routes/` | REST endpoints (projects, tasks, usage, services, events) |
| `backend/services/auth.py` | Password hashing, JWT encode/decode, SSE tokens, user management |
Expand Down Expand Up @@ -87,7 +90,7 @@ docker run -p 5200:5200 -v ./config.json:/app/config.json orchestration
- **DI Container**: `backend/container.py` wires all singletons; routes use `@inject` + `Depends(Provide[...])`
- **Database**: async SQLite via aiosqlite, WAL mode, all access via `Database` class
- **Migrations**: Alembic manages schema; `Database.init(run_migrations=True)` in production, inline schema in tests
- **Auth**: JWT Bearer tokens for REST, short-lived SSE tokens for EventSource. First registered user becomes admin.
- **Auth**: JWT Bearer tokens for REST, API keys (`orch_` prefix) for MCP/external executors, short-lived SSE tokens for EventSource. First registered user becomes admin.
- **Ownership**: projects have `owner_id`. Users see/modify only their own projects. Admins can access all.
- **Budget**: every API call recorded in `usage_log`, checked against limits before execution. Budget endpoints are admin-only.
- **Models**: Ollama (free) for simple tasks, Haiku ($) for medium, Sonnet ($$) for complex
Expand All @@ -103,8 +106,9 @@ docker run -p 5200:5200 -v ./config.json:/app/config.json orchestration
- **Verification**: optional post-completion check via Haiku (PASSED/GAPS_FOUND/HUMAN_NEEDED outcomes)
- **Checkpoints**: retry-exhausted tasks create structured checkpoints for human resolution
- **Traceability**: requirements numbered [R1], [R2], mapped to tasks; coverage endpoint shows gaps
- **External execution**: MCP server (`backend/mcp/server.py`) for Claude Code integration. Execution modes: auto (engine-only), hybrid (Ollama internal, Claude external), external (all external). Tasks claimed atomically via CAS, results submitted with cost tracking.
- **Git integration**: optional per-project (`repo_path` nullable). `GitService` wraps subprocess via `asyncio.to_thread()`. Config in `git.*` section. Phase 1 (foundation) complete; execution wiring (Phase 2+) pending.
- **Tests**: Backend: pytest-asyncio (auto mode), 578 tests, 86% coverage (CI threshold 80%). Frontend: vitest + @testing-library/react, 137 tests. Load tests: 7 (excluded from CI via `slow` marker)
- **Tests**: Backend: pytest-asyncio (auto mode), 731 tests. Frontend: vitest + @testing-library/react, 137 tests. Load tests: 7 (excluded from CI via `slow` marker)

## Git Workflow

Expand Down
2 changes: 2 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from backend.routes.auth_oidc import router as auth_oidc_router
from backend.routes.checkpoints import router as checkpoints_router
from backend.routes.events import router as events_router
from backend.routes.external import router as external_router
from backend.routes.projects import router as projects_router
from backend.routes.rag import router as rag_router
from backend.routes.services import health_router, router as services_router
Expand Down Expand Up @@ -252,6 +253,7 @@ async def send_with_headers(message):
app.include_router(admin_router, prefix="/api", dependencies=_auth_dep)
app.include_router(analytics_router, prefix="/api", dependencies=_auth_dep)
app.include_router(rag_router, prefix="/api", dependencies=_auth_dep)
app.include_router(external_router, prefix="/api", dependencies=_auth_dep)

# Events route uses query-param token auth (EventSource can't send headers)
app.include_router(events_router, prefix="/api")
Expand Down
1 change: 1 addition & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def cfg(path: str, default=None):
KNOWLEDGE_EXTRACTION_MAX_TOKENS = cfg("execution.knowledge_extraction_max_tokens", 1024)
KNOWLEDGE_INJECTION_MAX_CHARS = cfg("execution.knowledge_injection_max_chars", 3000)
KNOWLEDGE_MIN_OUTPUT_LENGTH = cfg("execution.knowledge_min_output_length", 200)
EXTERNAL_CLAIM_TIMEOUT_SECONDS = cfg("execution.external_claim_timeout_seconds", 3600)

# Model pricing
MODEL_PRICING = cfg("model_pricing", {})
Expand Down
1 change: 1 addition & 0 deletions backend/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Container(containers.DeclarativeContainer):
"backend.routes.analytics",
"backend.routes.rag",
"backend.routes.auth_oidc",
"backend.routes.external",
"backend.middleware.auth",
]
)
Expand Down
18 changes: 17 additions & 1 deletion backend/db/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
created_at REAL NOT NULL,
updated_at REAL NOT NULL,
git_branch TEXT,
git_commit_sha TEXT
git_commit_sha TEXT,
claimed_by TEXT,
claimed_at REAL
);

CREATE TABLE IF NOT EXISTS task_deps (
Expand Down Expand Up @@ -180,6 +182,20 @@
expires_at REAL NOT NULL
);

CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
key_hash TEXT NOT NULL UNIQUE,
key_prefix TEXT NOT NULL,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
is_active INTEGER NOT NULL DEFAULT 1,
created_at REAL NOT NULL,
last_used_at REAL
);

CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
CREATE INDEX IF NOT EXISTS idx_api_keys_user ON api_keys(user_id);

CREATE UNIQUE INDEX IF NOT EXISTS idx_rtf_token_hash
ON refresh_token_families(token_hash);
CREATE INDEX IF NOT EXISTS idx_rtf_family_id
Expand Down
17 changes: 17 additions & 0 deletions backend/db/models_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
Column("updated_at", Float, nullable=False),
Column("git_branch", Text),
Column("git_commit_sha", Text),
Column("claimed_by", Text),
Column("claimed_at", Float),
)

task_deps = Table(
Expand Down Expand Up @@ -201,7 +203,22 @@
Column("created_at", Float, nullable=False),
)

api_keys = Table(
"api_keys",
metadata,
Column("id", Text, primary_key=True),
Column("key_hash", Text, nullable=False, unique=True),
Column("key_prefix", Text, nullable=False),
Column("user_id", Text, ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
Column("name", Text, nullable=False),
Column("is_active", Integer, nullable=False, server_default="1"),
Column("created_at", Float, nullable=False),
Column("last_used_at", Float),
)

# Indexes
Index("idx_api_keys_hash", api_keys.c.key_hash)
Index("idx_api_keys_user", api_keys.c.user_id)
Index("idx_identities_user", user_identities.c.user_id)
Index("idx_identities_provider_uid", user_identities.c.provider, user_identities.c.provider_user_id, unique=True)
Index("idx_checkpoints_project", checkpoints.c.project_id)
Expand Down
6 changes: 6 additions & 0 deletions backend/mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Orchestration Engine - MCP Package
#
# FastMCP stdio server for Claude Code integration.
#
# Depends on: (none at package level)
# Used by: Claude Code MCP settings
5 changes: 5 additions & 0 deletions backend/mcp/config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"api_url": "http://localhost:5200",
"api_key": "orch_YOUR_API_KEY_HERE",
"timeout": 300
}
Loading