From e7819bfc8258e1b736eada181d602025ab168f97 Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Sat, 16 May 2026 17:44:39 +0000 Subject: [PATCH] feat: implement docker infrastructure (US-001) - Add docker-compose.yml with postgres, redis, api, and web services - Add multi-stage Dockerfile for API (Python 3.11) - Add multi-stage Dockerfile for web (Node.js 20 + nginx) - Add Makefile with common development commands - Add .env.example with all required environment variables - Add placeholder pyproject.toml and package.json for builds - Configure health checks for all services - Setup persistent volumes for postgres, redis, and repos - Run services as non-root users --- .beads/.gitignore | 73 - .beads/README.md | 81 - .beads/beads.jsonl | 22 - .beads/config.yaml | 54 - .beads/hooks/post-checkout | 24 - .beads/hooks/post-merge | 24 - .beads/hooks/pre-commit | 24 - .beads/hooks/pre-push | 24 - .beads/hooks/prepare-commit-msg | 24 - .beads/metadata.json | 7 - .claude/settings.json | 26 - .editorconfig | 15 - .env.example | 54 +- .github/workflows/ci.yml | 87 - .opencode/commands/opsx-apply.md | 149 + .opencode/commands/opsx-archive.md | 154 + .opencode/commands/opsx-explore.md | 170 + .opencode/commands/opsx-propose.md | 103 + .../skills/openspec-apply-change/SKILL.md | 156 + .../skills/openspec-archive-change/SKILL.md | 114 + .opencode/skills/openspec-explore/SKILL.md | 288 ++ .opencode/skills/openspec-propose/SKILL.md | 110 + AGENTS.md | 141 +- CLAUDE.md | 69 - Makefile | 94 + README.md | 137 - apps/api/.dockerignore | 15 - apps/api/.python-version | 1 - apps/api/Dockerfile | 49 +- apps/api/Makefile | 19 - apps/api/alembic.ini | 149 - apps/api/alembic/README | 1 - apps/api/alembic/env.py | 76 - apps/api/alembic/script.py.mako | 28 - .../42a78fd41e23_add_repository_connection.py | 51 - .../versions/6cfa61694d0a_initial_schema.py | 172 - apps/api/app/__init__.py | 0 apps/api/app/auth/__init__.py | 3 - apps/api/app/auth/dependencies.py | 150 - apps/api/app/auth/jwt.py | 58 - apps/api/app/config.py | 36 - apps/api/app/db.py | 25 - apps/api/app/encryption.py | 30 - apps/api/app/git/__init__.py | 25 - apps/api/app/git/connection.py | 100 - apps/api/app/git/credential_storage.py | 39 - apps/api/app/git/credentials.py | 52 - apps/api/app/git/operations.py | 100 - apps/api/app/git/provider.py | 48 - apps/api/app/git/providers/__init__.py | 17 - apps/api/app/git/providers/github.py | 40 - apps/api/app/git/providers/gitlab.py | 35 - apps/api/app/git/ssh_key.py | 82 - apps/api/app/git/types.py | 38 - apps/api/app/main.py | 65 - apps/api/app/models/__init__.py | 27 - apps/api/app/models/access_route.py | 35 - apps/api/app/models/base.py | 26 - apps/api/app/models/config.py | 22 - apps/api/app/models/credential.py | 16 - apps/api/app/models/project.py | 36 - apps/api/app/models/repository.py | 34 - apps/api/app/models/repository_connection.py | 42 - apps/api/app/models/secret.py | 18 - apps/api/app/models/tool_definition.py | 32 - apps/api/app/models/tool_instance.py | 49 - apps/api/app/models/user.py | 30 - apps/api/app/models/workspace.py | 24 - apps/api/app/routers/__init__.py | 27 - apps/api/app/routers/access_routes.py | 103 - apps/api/app/routers/configs.py | 122 - apps/api/app/routers/projects.py | 80 - apps/api/app/routers/repositories.py | 100 - .../api/app/routers/repository_connections.py | 243 -- apps/api/app/routers/secrets.py | 129 - apps/api/app/routers/tool_definitions.py | 88 - apps/api/app/routers/tool_instances.py | 327 -- apps/api/app/routers/users.py | 17 - apps/api/app/routers/workspaces.py | 100 - apps/api/app/schemas/__init__.py | 42 - apps/api/app/schemas/access_route.py | 29 - apps/api/app/schemas/base.py | 5 - apps/api/app/schemas/config.py | 25 - apps/api/app/schemas/project.py | 24 - apps/api/app/schemas/repository.py | 26 - apps/api/app/schemas/repository_connection.py | 35 - apps/api/app/schemas/secret.py | 39 - apps/api/app/schemas/tool_definition.py | 29 - apps/api/app/schemas/tool_instance.py | 32 - apps/api/app/schemas/user.py | 21 - apps/api/app/schemas/workspace.py | 22 - apps/api/app/services/runtime_injection.py | 135 - apps/api/app/services/spawn.py | 345 -- apps/api/app/services/traefik.py | 101 - apps/api/app/tools/__init__.py | 0 apps/api/app/tools/manifests/__init__.py | 0 apps/api/app/tools/manifests/code-server.yml | 52 - apps/api/app/tools/manifests/opencode.yml | 42 - apps/api/app/tools/models.py | 109 - apps/api/app/tools/registry.py | 52 - apps/api/app/tools/router.py | 37 - apps/api/package.json | 12 - apps/api/pyproject.toml | 66 +- apps/api/tests/__init__.py | 0 apps/api/tests/conftest.py | 90 - apps/api/tests/test_auth.py | 87 - apps/api/tests/test_git_credentials.py | 77 - apps/api/tests/test_git_operations.py | 147 - apps/api/tests/test_git_provider.py | 66 - apps/api/tests/test_health.py | 14 - apps/api/tests/test_routers/__init__.py | 0 apps/api/tests/test_routers/test_projects.py | 35 - .../tests/test_routers/test_repositories.py | 40 - apps/api/tests/test_routers/test_secrets.py | 72 - .../test_routers/test_tool_definitions.py | 30 - apps/api/tests/test_runtime_injection.py | 110 - apps/api/tests/test_traefik.py | 197 - apps/api/tests/tools/test_models.py | 241 -- apps/api/tests/tools/test_registry.py | 159 - apps/api/tests/tools/test_router.py | 93 - apps/web/.dockerignore | 6 - apps/web/.env.example | 8 - apps/web/.npmrc | 1 - apps/web/Dockerfile | 51 +- apps/web/eslint.config.js | 28 - apps/web/index.html | 12 - apps/web/nginx.conf | 29 +- apps/web/package.json | 61 +- apps/web/src/App.css | 70 - apps/web/src/App.tsx | 13 - apps/web/src/__tests__/App.test.tsx | 21 - apps/web/src/__tests__/setup.ts | 26 - apps/web/src/api/client.ts | 306 -- apps/web/src/auth/AuthProvider.tsx | 50 - apps/web/src/auth/oidc.ts | 58 - apps/web/src/components/DashboardLayout.tsx | 17 - apps/web/src/components/Header.tsx | 59 - apps/web/src/components/RouteGuard.tsx | 20 - apps/web/src/components/Sidebar.tsx | 48 - apps/web/src/env.d.ts | 12 - apps/web/src/index.css | 56 - apps/web/src/main.tsx | 23 - apps/web/src/pages/CallbackPage.tsx | 111 - apps/web/src/pages/ConfigListPage.tsx | 183 - apps/web/src/pages/DashboardPage.tsx | 28 - apps/web/src/pages/LoginPage.tsx | 47 - apps/web/src/pages/ProjectDetailPage.tsx | 38 - apps/web/src/pages/ProjectFormPage.tsx | 135 - apps/web/src/pages/ProjectListPage.tsx | 86 - apps/web/src/pages/RepositoriesPage.tsx | 8 - apps/web/src/pages/RepositoryDetailPage.tsx | 193 - apps/web/src/pages/RepositoryListPage.tsx | 129 - apps/web/src/pages/SecretListPage.tsx | 181 - apps/web/src/pages/SettingsPage.tsx | 26 - apps/web/src/pages/ToolInstanceDetailPage.tsx | 222 -- apps/web/src/pages/ToolSpawnPage.tsx | 163 - apps/web/src/pages/ToolsPage.tsx | 8 - apps/web/src/router.tsx | 51 - apps/web/src/stores/auth.ts | 27 - apps/web/src/types/api.ts | 120 - apps/web/tsconfig.app.json | 25 - apps/web/tsconfig.json | 7 - apps/web/tsconfig.node.json | 19 - apps/web/vite.config.ts | 28 - docker-compose.prod.yml | 137 - docker-compose.traefik.yml | 92 - docker-compose.yml | 112 +- docs/README.md | 20 - docs/architecture.md | 1214 ------- docs/conversation-handoff.md | 68 - docs/deployment.md | 133 - docs/development.md | 453 --- docs/mvp-scope.md | 184 - docs/project-brief.md | 31 - .../plans/2024-05-16-docker-infrastructure.md | 726 ++++ docs/tool-manifest-spec.md | 205 -- openspec/README.md | 170 + .../.openspec.yaml | 2 - .../2026-05-14-codeserver-spawn/design.md | 67 - .../2026-05-14-codeserver-spawn/proposal.md | 31 - .../specs/codeserver-manifest/spec.md | 23 - .../specs/container-lifecycle/spec.md | 29 - .../specs/spawn-ui/spec.md | 21 - .../specs/tool-spawn-api/spec.md | 29 - .../2026-05-14-codeserver-spawn/tasks.md | 58 - .../2026-05-14-config-secrets/.openspec.yaml | 2 - .../2026-05-14-config-secrets/design.md | 63 - .../2026-05-14-config-secrets/proposal.md | 29 - .../specs/config-management/spec.md | 37 - .../specs/runtime-injection/spec.md | 40 - .../specs/secret-management/spec.md | 37 - .../2026-05-14-config-secrets/tasks.md | 48 - .../.openspec.yaml | 2 - .../2026-05-14-deployment-config/design.md | 67 - .../2026-05-14-deployment-config/proposal.md | 31 - .../specs/portainer-deployment/spec.md | 22 - .../specs/production-compose-stack/spec.md | 28 - .../specs/subdomain-routing/spec.md | 23 - .../specs/traefik-label-generator/spec.md | 24 - .../2026-05-14-deployment-config/tasks.md | 44 - .../.openspec.yaml | 2 - .../2026-05-14-frontend-foundation/design.md | 75 - .../proposal.md | 32 - .../specs/api-client/spec.md | 28 - .../specs/auth-oidc/spec.md | 36 - .../specs/dashboard-shell/spec.md | 28 - .../specs/project-management-ui/spec.md | 39 - .../specs/route-guards/spec.md | 24 - .../2026-05-14-frontend-foundation/tasks.md | 72 - .../2026-05-14-runfusion-poc/.openspec.yaml | 2 - .../2026-05-14-runfusion-poc/design.md | 65 - .../2026-05-14-runfusion-poc/proposal.md | 28 - .../specs/executable-environment/spec.md | 27 - .../specs/health-reporting/spec.md | 22 - .../specs/runfusion-manifest/spec.md | 15 - .../archive/2026-05-14-runfusion-poc/tasks.md | 42 - .../.openspec.yaml | 2 - .../git-connection-model/.openspec.yaml | 2 - .../changes/git-connection-model/design.md | 79 - .../changes/git-connection-model/proposal.md | 39 - .../specs/credential-storage/spec.md | 30 - .../specs/git-operations/spec.md | 29 - .../specs/git-provider-adapter/spec.md | 35 - .../specs/repository-connection/spec.md | 42 - .../specs/ssh-key-lifecycle/spec.md | 28 - .../changes/git-connection-model/tasks.md | 63 - openspec/config.yaml | 48 - openspec/specs/api-documentation/spec.md | 94 + openspec/specs/auth-oauth/spec.md | 66 + openspec/specs/database-models/spec.md | 127 + openspec/specs/docker-infrastructure/spec.md | 113 + openspec/specs/frontend-foundation/spec.md | 134 + openspec/specs/git-repo/spec.md | 68 + openspec/specs/project-management/spec.md | 69 + openspec/specs/project-specsheet.md | 243 -- openspec/specs/ssh-keys/spec.md | 65 + openspec/specs/tool-instances/spec.md | 90 + openspec/specs/tool-terminal/spec.md | 76 + openspec/specs/tool-types/spec.md | 67 + openspec/specs/user-config/spec.md | 69 + openspec/specs/user-profile/spec.md | 50 + package.json | 11 - pnpm-lock.yaml | 3232 ----------------- pnpm-workspace.yaml | 3 - tests/docs/__init__.py | 0 tests/docs/test_architecture.py | 120 - 246 files changed, 3625 insertions(+), 17311 deletions(-) delete mode 100644 .beads/.gitignore delete mode 100644 .beads/README.md delete mode 100644 .beads/beads.jsonl delete mode 100644 .beads/config.yaml delete mode 100755 .beads/hooks/post-checkout delete mode 100755 .beads/hooks/post-merge delete mode 100755 .beads/hooks/pre-commit delete mode 100755 .beads/hooks/pre-push delete mode 100755 .beads/hooks/prepare-commit-msg delete mode 100644 .beads/metadata.json delete mode 100644 .claude/settings.json delete mode 100644 .editorconfig delete mode 100644 .github/workflows/ci.yml create mode 100644 .opencode/commands/opsx-apply.md create mode 100644 .opencode/commands/opsx-archive.md create mode 100644 .opencode/commands/opsx-explore.md create mode 100644 .opencode/commands/opsx-propose.md create mode 100644 .opencode/skills/openspec-apply-change/SKILL.md create mode 100644 .opencode/skills/openspec-archive-change/SKILL.md create mode 100644 .opencode/skills/openspec-explore/SKILL.md create mode 100644 .opencode/skills/openspec-propose/SKILL.md delete mode 100644 CLAUDE.md create mode 100644 Makefile delete mode 100644 README.md delete mode 100644 apps/api/.dockerignore delete mode 100644 apps/api/.python-version delete mode 100644 apps/api/Makefile delete mode 100644 apps/api/alembic.ini delete mode 100644 apps/api/alembic/README delete mode 100644 apps/api/alembic/env.py delete mode 100644 apps/api/alembic/script.py.mako delete mode 100644 apps/api/alembic/versions/42a78fd41e23_add_repository_connection.py delete mode 100644 apps/api/alembic/versions/6cfa61694d0a_initial_schema.py delete mode 100644 apps/api/app/__init__.py delete mode 100644 apps/api/app/auth/__init__.py delete mode 100644 apps/api/app/auth/dependencies.py delete mode 100644 apps/api/app/auth/jwt.py delete mode 100644 apps/api/app/config.py delete mode 100644 apps/api/app/db.py delete mode 100644 apps/api/app/encryption.py delete mode 100644 apps/api/app/git/__init__.py delete mode 100644 apps/api/app/git/connection.py delete mode 100644 apps/api/app/git/credential_storage.py delete mode 100644 apps/api/app/git/credentials.py delete mode 100644 apps/api/app/git/operations.py delete mode 100644 apps/api/app/git/provider.py delete mode 100644 apps/api/app/git/providers/__init__.py delete mode 100644 apps/api/app/git/providers/github.py delete mode 100644 apps/api/app/git/providers/gitlab.py delete mode 100644 apps/api/app/git/ssh_key.py delete mode 100644 apps/api/app/git/types.py delete mode 100644 apps/api/app/main.py delete mode 100644 apps/api/app/models/__init__.py delete mode 100644 apps/api/app/models/access_route.py delete mode 100644 apps/api/app/models/base.py delete mode 100644 apps/api/app/models/config.py delete mode 100644 apps/api/app/models/credential.py delete mode 100644 apps/api/app/models/project.py delete mode 100644 apps/api/app/models/repository.py delete mode 100644 apps/api/app/models/repository_connection.py delete mode 100644 apps/api/app/models/secret.py delete mode 100644 apps/api/app/models/tool_definition.py delete mode 100644 apps/api/app/models/tool_instance.py delete mode 100644 apps/api/app/models/user.py delete mode 100644 apps/api/app/models/workspace.py delete mode 100644 apps/api/app/routers/__init__.py delete mode 100644 apps/api/app/routers/access_routes.py delete mode 100644 apps/api/app/routers/configs.py delete mode 100644 apps/api/app/routers/projects.py delete mode 100644 apps/api/app/routers/repositories.py delete mode 100644 apps/api/app/routers/repository_connections.py delete mode 100644 apps/api/app/routers/secrets.py delete mode 100644 apps/api/app/routers/tool_definitions.py delete mode 100644 apps/api/app/routers/tool_instances.py delete mode 100644 apps/api/app/routers/users.py delete mode 100644 apps/api/app/routers/workspaces.py delete mode 100644 apps/api/app/schemas/__init__.py delete mode 100644 apps/api/app/schemas/access_route.py delete mode 100644 apps/api/app/schemas/base.py delete mode 100644 apps/api/app/schemas/config.py delete mode 100644 apps/api/app/schemas/project.py delete mode 100644 apps/api/app/schemas/repository.py delete mode 100644 apps/api/app/schemas/repository_connection.py delete mode 100644 apps/api/app/schemas/secret.py delete mode 100644 apps/api/app/schemas/tool_definition.py delete mode 100644 apps/api/app/schemas/tool_instance.py delete mode 100644 apps/api/app/schemas/user.py delete mode 100644 apps/api/app/schemas/workspace.py delete mode 100644 apps/api/app/services/runtime_injection.py delete mode 100644 apps/api/app/services/spawn.py delete mode 100644 apps/api/app/services/traefik.py delete mode 100644 apps/api/app/tools/__init__.py delete mode 100644 apps/api/app/tools/manifests/__init__.py delete mode 100644 apps/api/app/tools/manifests/code-server.yml delete mode 100644 apps/api/app/tools/manifests/opencode.yml delete mode 100644 apps/api/app/tools/models.py delete mode 100644 apps/api/app/tools/registry.py delete mode 100644 apps/api/app/tools/router.py delete mode 100644 apps/api/package.json delete mode 100644 apps/api/tests/__init__.py delete mode 100644 apps/api/tests/conftest.py delete mode 100644 apps/api/tests/test_auth.py delete mode 100644 apps/api/tests/test_git_credentials.py delete mode 100644 apps/api/tests/test_git_operations.py delete mode 100644 apps/api/tests/test_git_provider.py delete mode 100644 apps/api/tests/test_health.py delete mode 100644 apps/api/tests/test_routers/__init__.py delete mode 100644 apps/api/tests/test_routers/test_projects.py delete mode 100644 apps/api/tests/test_routers/test_repositories.py delete mode 100644 apps/api/tests/test_routers/test_secrets.py delete mode 100644 apps/api/tests/test_routers/test_tool_definitions.py delete mode 100644 apps/api/tests/test_runtime_injection.py delete mode 100644 apps/api/tests/test_traefik.py delete mode 100644 apps/api/tests/tools/test_models.py delete mode 100644 apps/api/tests/tools/test_registry.py delete mode 100644 apps/api/tests/tools/test_router.py delete mode 100644 apps/web/.dockerignore delete mode 100644 apps/web/.env.example delete mode 100644 apps/web/.npmrc delete mode 100644 apps/web/eslint.config.js delete mode 100644 apps/web/index.html delete mode 100644 apps/web/src/App.css delete mode 100644 apps/web/src/App.tsx delete mode 100644 apps/web/src/__tests__/App.test.tsx delete mode 100644 apps/web/src/__tests__/setup.ts delete mode 100644 apps/web/src/api/client.ts delete mode 100644 apps/web/src/auth/AuthProvider.tsx delete mode 100644 apps/web/src/auth/oidc.ts delete mode 100644 apps/web/src/components/DashboardLayout.tsx delete mode 100644 apps/web/src/components/Header.tsx delete mode 100644 apps/web/src/components/RouteGuard.tsx delete mode 100644 apps/web/src/components/Sidebar.tsx delete mode 100644 apps/web/src/env.d.ts delete mode 100644 apps/web/src/index.css delete mode 100644 apps/web/src/main.tsx delete mode 100644 apps/web/src/pages/CallbackPage.tsx delete mode 100644 apps/web/src/pages/ConfigListPage.tsx delete mode 100644 apps/web/src/pages/DashboardPage.tsx delete mode 100644 apps/web/src/pages/LoginPage.tsx delete mode 100644 apps/web/src/pages/ProjectDetailPage.tsx delete mode 100644 apps/web/src/pages/ProjectFormPage.tsx delete mode 100644 apps/web/src/pages/ProjectListPage.tsx delete mode 100644 apps/web/src/pages/RepositoriesPage.tsx delete mode 100644 apps/web/src/pages/RepositoryDetailPage.tsx delete mode 100644 apps/web/src/pages/RepositoryListPage.tsx delete mode 100644 apps/web/src/pages/SecretListPage.tsx delete mode 100644 apps/web/src/pages/SettingsPage.tsx delete mode 100644 apps/web/src/pages/ToolInstanceDetailPage.tsx delete mode 100644 apps/web/src/pages/ToolSpawnPage.tsx delete mode 100644 apps/web/src/pages/ToolsPage.tsx delete mode 100644 apps/web/src/router.tsx delete mode 100644 apps/web/src/stores/auth.ts delete mode 100644 apps/web/src/types/api.ts delete mode 100644 apps/web/tsconfig.app.json delete mode 100644 apps/web/tsconfig.json delete mode 100644 apps/web/tsconfig.node.json delete mode 100644 apps/web/vite.config.ts delete mode 100644 docker-compose.prod.yml delete mode 100644 docker-compose.traefik.yml delete mode 100644 docs/README.md delete mode 100644 docs/architecture.md delete mode 100644 docs/conversation-handoff.md delete mode 100644 docs/deployment.md delete mode 100644 docs/development.md delete mode 100644 docs/mvp-scope.md delete mode 100644 docs/project-brief.md create mode 100644 docs/superpowers/plans/2024-05-16-docker-infrastructure.md delete mode 100644 docs/tool-manifest-spec.md create mode 100644 openspec/README.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/design.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/proposal.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/specs/codeserver-manifest/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/specs/container-lifecycle/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/specs/spawn-ui/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/specs/tool-spawn-api/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-codeserver-spawn/tasks.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/design.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/proposal.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/specs/config-management/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/specs/runtime-injection/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/specs/secret-management/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-config-secrets/tasks.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/design.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/proposal.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/specs/portainer-deployment/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/specs/production-compose-stack/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/specs/subdomain-routing/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/specs/traefik-label-generator/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-deployment-config/tasks.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/design.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/proposal.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/specs/api-client/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/specs/auth-oidc/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/specs/dashboard-shell/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/specs/project-management-ui/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/specs/route-guards/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-frontend-foundation/tasks.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/.openspec.yaml delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/design.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/proposal.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/specs/executable-environment/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/specs/health-reporting/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/specs/runfusion-manifest/spec.md delete mode 100644 openspec/changes/archive/2026-05-14-runfusion-poc/tasks.md delete mode 100644 openspec/changes/fn-007-git-connection-model/.openspec.yaml delete mode 100644 openspec/changes/git-connection-model/.openspec.yaml delete mode 100644 openspec/changes/git-connection-model/design.md delete mode 100644 openspec/changes/git-connection-model/proposal.md delete mode 100644 openspec/changes/git-connection-model/specs/credential-storage/spec.md delete mode 100644 openspec/changes/git-connection-model/specs/git-operations/spec.md delete mode 100644 openspec/changes/git-connection-model/specs/git-provider-adapter/spec.md delete mode 100644 openspec/changes/git-connection-model/specs/repository-connection/spec.md delete mode 100644 openspec/changes/git-connection-model/specs/ssh-key-lifecycle/spec.md delete mode 100644 openspec/changes/git-connection-model/tasks.md delete mode 100644 openspec/config.yaml create mode 100644 openspec/specs/api-documentation/spec.md create mode 100644 openspec/specs/auth-oauth/spec.md create mode 100644 openspec/specs/database-models/spec.md create mode 100644 openspec/specs/docker-infrastructure/spec.md create mode 100644 openspec/specs/frontend-foundation/spec.md create mode 100644 openspec/specs/git-repo/spec.md create mode 100644 openspec/specs/project-management/spec.md delete mode 100644 openspec/specs/project-specsheet.md create mode 100644 openspec/specs/ssh-keys/spec.md create mode 100644 openspec/specs/tool-instances/spec.md create mode 100644 openspec/specs/tool-terminal/spec.md create mode 100644 openspec/specs/tool-types/spec.md create mode 100644 openspec/specs/user-config/spec.md create mode 100644 openspec/specs/user-profile/spec.md delete mode 100644 package.json delete mode 100644 pnpm-lock.yaml delete mode 100644 pnpm-workspace.yaml delete mode 100644 tests/docs/__init__.py delete mode 100644 tests/docs/test_architecture.py diff --git a/.beads/.gitignore b/.beads/.gitignore deleted file mode 100644 index df4911d..0000000 --- a/.beads/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Dolt database (managed by Dolt, not git) -dolt/ -embeddeddolt/ - -# Runtime files -bd.sock -bd.sock.startlock -sync-state.json -last-touched -.exclusive-lock - -# Daemon runtime (lock, log, pid) -daemon.* - -# Interactions log (runtime, not versioned) -interactions.jsonl - -# Push state (runtime, per-machine) -push-state.json - -# Lock files (various runtime locks) -*.lock - -# Credential key (encryption key for federation peer auth — never commit) -.beads-credential-key - -# Local version tracking (prevents upgrade notification spam after git ops) -.local_version - -# Worktree redirect file (contains relative path to main repo's .beads/) -# Must not be committed as paths would be wrong in other clones -redirect - -# Sync state (local-only, per-machine) -# These files are machine-specific and should not be shared across clones -.sync.lock -export-state/ -export-state.json - -# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned) -ephemeral.sqlite3 -ephemeral.sqlite3-journal -ephemeral.sqlite3-wal -ephemeral.sqlite3-shm - -# Dolt server management (auto-started by bd) -dolt-server.pid -dolt-server.log -dolt-server.lock -dolt-server.port -dolt-server.activity - -# Corrupt backup directories (created by bd doctor --fix recovery) -*.corrupt.backup/ - -# Backup data (auto-exported JSONL, local-only) -backup/ - -# Per-project environment file (Dolt connection config, GH#2520) -.env - -# Legacy files (from pre-Dolt versions) -*.db -*.db?* -*.db-journal -*.db-wal -*.db-shm -db.sqlite -bd.db -# NOTE: Do NOT add negation patterns here. -# They would override fork protection in .git/info/exclude. -# Config files (metadata.json, config.yaml) are tracked by git by default -# since no pattern above ignores them. diff --git a/.beads/README.md b/.beads/README.md deleted file mode 100644 index dbfe363..0000000 --- a/.beads/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Beads - AI-Native Issue Tracking - -Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code. - -## What is Beads? - -Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git. - -**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads) - -## Quick Start - -### Essential Commands - -```bash -# Create new issues -bd create "Add user authentication" - -# View all issues -bd list - -# View issue details -bd show - -# Update issue status -bd update --claim -bd update --status done - -# Sync with Dolt remote -bd dolt push -``` - -### Working with Issues - -Issues in Beads are: -- **Git-native**: Stored in Dolt database with version control and branching -- **AI-friendly**: CLI-first design works perfectly with AI coding agents -- **Branch-aware**: Issues can follow your branch workflow -- **Always in sync**: Auto-syncs with your commits - -## Why Beads? - -✨ **AI-Native Design** -- Built specifically for AI-assisted development workflows -- CLI-first interface works seamlessly with AI coding agents -- No context switching to web UIs - -🚀 **Developer Focused** -- Issues live in your repo, right next to your code -- Works offline, syncs when you push -- Fast, lightweight, and stays out of your way - -🔧 **Git Integration** -- Automatic sync with git commits -- Branch-aware issue tracking -- Dolt-native three-way merge resolution - -## Get Started with Beads - -Try Beads in your own projects: - -```bash -# Install Beads -curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash - -# Initialize in your repo -bd init - -# Create your first issue -bd create "Try out Beads" -``` - -## Learn More - -- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs) -- **Quick Start Guide**: Run `bd quickstart` -- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples) - ---- - -*Beads: Issue tracking that moves at the speed of thought* ⚡ diff --git a/.beads/beads.jsonl b/.beads/beads.jsonl deleted file mode 100644 index aeaed20..0000000 --- a/.beads/beads.jsonl +++ /dev/null @@ -1,22 +0,0 @@ -{"id":"phase1-epic","type":"epic","title":"Phase 1: Foundation (Auth, Git Repos, Project Structure)","description":"Rebuild Headquarter platform from scratch starting with foundational layer: Authentik OAuth auth, git repository management with bare repos on disk, SSH key management, user profiles, and basic project structure. Provides core infrastructure for Phase 2 (tool spawning) and Phase 3 (collaboration).","status":"open","priority":0,"parent":null,"external_ref":"prd:./tasks/prd-phase1-foundation.md","dependencies":[]} -{"id":"phase1-001","type":"story","title":"US-001: Docker Infrastructure & Project Bootstrap","description":"As a developer, I want a Docker Compose setup with all required services so that I can run the platform locally.\n\n## Acceptance Criteria\n- [ ] `docker-compose.yml` with PostgreSQL, Redis, Traefik, and Authentik services\n- [ ] `apps/api/Dockerfile` with multi-stage build for FastAPI\n- [ ] `apps/web/Dockerfile` for React SPA with Vite\n- [ ] `.env.example` documenting all required environment variables\n- [ ] Health checks for all services\n- [ ] `Makefile` with common commands (`make up`, `make down`, `make logs`, `make migrate`)\n- [ ] Git repo storage directory mounted as Docker volume\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":[]} -{"id":"phase1-002","type":"story","title":"US-002: Database Models & Alembic Migrations","description":"As a developer, I want database models for users, projects, and git repos so that the data layer is consistent and versioned.\n\n## Acceptance Criteria\n- [ ] SQLAlchemy models: User, Project, GitRepository, SSHKey, UserConfig\n- [ ] Relationships: User owns Projects, Project has GitRepositories, User has SSHKeys\n- [ ] Alembic initialized with initial migration script\n- [ ] Migration command documented in Makefile\n- [ ] Database seed script for development (creates test user)\n- [ ] All models use SQLAlchemy 2.0 async style\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":[]} -{"id":"phase1-003","type":"story","title":"US-003: Authentik OAuth Authentication with httpOnly Cookies","description":"As a user, I want to log in via Authentik OAuth with secure httpOnly cookies so that my session is protected from XSS attacks.\n\n## Acceptance Criteria\n- [ ] OAuth2/OIDC flow implemented with Authentik as provider\n- [ ] Callback endpoint exchanges code for tokens and sets httpOnly, Secure, SameSite=strict cookies\n- [ ] Token refresh mechanism with refresh token rotation\n- [ ] `/auth/me` endpoint returning current authenticated user\n- [ ] `/auth/logout` endpoint clearing all auth cookies\n- [ ] JWT validation middleware protecting all API routes (except public)\n- [ ] Frontend login button redirecting to Authentik\n- [ ] Frontend handles OAuth callback and refreshes user state\n- [ ] Tests mocking Authentik OIDC endpoints\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":1,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]} -{"id":"phase1-004","type":"story","title":"US-004: User Profile Management","description":"As a user, I want to view and edit my profile so that my information is up to date.\n\n## Acceptance Criteria\n- [ ] `GET /users/me` endpoint returning current user profile\n- [ ] `PATCH /users/me` endpoint for updating profile fields (name, email)\n- [ ] Frontend profile page displaying user info\n- [ ] Frontend profile edit form with validation\n- [ ] Avatar upload support (stored locally, not external service)\n- [ ] Tests for profile CRUD operations\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]} -{"id":"phase1-005","type":"story","title":"US-005: Git Repository Creation & Cloning","description":"As a user, I want to create new git repositories or clone existing ones so that I can start working on projects.\n\n## Acceptance Criteria\n- [ ] `POST /repos` endpoint to create a new bare git repository\n- [ ] `POST /repos/clone` endpoint to clone an existing repo (bare mirror)\n- [ ] Repositories stored as bare repos on disk in structured path (`/data/repos/{user_id}/{project_id}/{repo_name}.git`)\n- [ ] `GET /repos` listing all user repositories\n- [ ] `GET /repos/{id}` returning repo details (name, path, created_at, last_push)\n- [ ] `DELETE /repos/{id}` removing repo from disk and database\n- [ ] Validation preventing duplicate repo names per project\n- [ ] Frontend repo list page\n- [ ] Frontend forms for create and clone operations\n- [ ] Tests for repo lifecycle (create, clone, delete)\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]} -{"id":"phase1-006","type":"story","title":"US-006: SSH Key Management","description":"As a user, I want to generate and manage SSH keys for git operations so that I can authenticate with external git providers.\n\n## Acceptance Criteria\n- [ ] `POST /ssh-keys` endpoint generating Ed25519 key pair\n- [ ] `GET /ssh-keys` listing user's SSH keys\n- [ ] `DELETE /ssh-keys/{id}` removing a key\n- [ ] Public key displayed in OpenSSH format\n- [ ] Private key encrypted at rest (using Fernet with app secret)\n- [ ] SSH keys associated with User (global) or Project (project-specific)\n- [ ] Frontend SSH key management page\n- [ ] Frontend key generation with one-click copy of public key\n- [ ] Tests for key generation and encryption\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002"]} -{"id":"phase1-007","type":"story","title":"US-007: Project Structure & Organization","description":"As a user, I want to organize repositories into projects so that I can group related work.\n\n## Acceptance Criteria\n- [ ] `POST /projects` endpoint creating a new project\n- [ ] `GET /projects` listing user's projects\n- [ ] `GET /projects/{id}` returning project with associated repos\n- [ ] `PATCH /projects/{id}` updating project name/description\n- [ ] `DELETE /projects/{id}` deleting project and all associated repos\n- [ ] Project settings page for default SSH key selection\n- [ ] Frontend project list and detail pages\n- [ ] Frontend project creation form\n- [ ] Tests for project CRUD and cascading delete\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-002","phase1-005"]} -{"id":"phase1-008","type":"story","title":"US-008: User Configuration System","description":"As a user, I want to set global preferences so that the platform behaves according to my preferences.\n\n## Acceptance Criteria\n- [ ] `UserConfig` model with key-value storage (JSONB)\n- [ ] `GET /config` endpoint returning user configuration\n- [ ] `PATCH /config` endpoint updating configuration\n- [ ] Supported config keys: default_editor, theme, git_user_name, git_user_email\n- [ ] Frontend settings page with config form\n- [ ] Config applied on frontend (theme, default values)\n- [ ] Tests for config CRUD\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]} -{"id":"phase1-009","type":"story","title":"US-009: Frontend Foundation & Layout","description":"As a user, I want a modern React frontend with navigation so that I can access all features.\n\n## Acceptance Criteria\n- [ ] React 18+ with TypeScript and Vite\n- [ ] React Router setup with protected routes\n- [ ] Tailwind CSS for styling\n- [ ] Layout component with header, sidebar navigation, and main content area\n- [ ] Navigation links: Dashboard, Projects, Repositories, SSH Keys, Settings\n- [ ] Responsive design (mobile hamburger menu)\n- [ ] Loading states and error boundaries\n- [ ] Axios/fetch configured with credentials (cookies)\n- [ ] Basic dashboard page showing user stats (repo count, project count)\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass\n- `npm run typecheck` must pass\n- `npm run lint` must pass","status":"open","priority":2,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003","phase1-004"]} -{"id":"phase1-010","type":"story","title":"US-010: API Documentation & Health Checks","description":"As a developer, I want API documentation and health endpoints so that I can monitor and integrate with the platform.\n\n## Acceptance Criteria\n- [ ] OpenAPI/Swagger UI at `/docs` with all endpoints documented\n- [ ] `/health` endpoint returning database and service status\n- [ ] `/health/db` endpoint for database connectivity check\n- [ ] README in `apps/api/` with setup instructions\n- [ ] Architecture Decision Record (ADR) for httpOnly cookie auth choice\n- [ ] All quality gates passing\n\n## Quality Gates\n- `pytest` must pass\n- `mypy .` must pass\n- `ruff check .` must pass","status":"open","priority":3,"parent":"phase1-epic","external_ref":null,"dependencies":["phase1-003"]} -{"id":"phase2-epic","type":"epic","title":"Phase 2: Tool Runtime (Docker Tools, Web Access, Terminal)","description":"Extend Headquarter platform with Docker-based tool runtime system. Enables launching development tools (code-server, Jupyter, opencode) from git repositories, accessing their web UIs via Traefik routes, and interacting through web-based terminals. Tools are defined via Docker Compose templates and spawned into isolated containers.","status":"open","priority":0,"parent":null,"external_ref":"prd:./tasks/prd-phase2-tool-runtime.md","dependencies":[]} -{"id":"phase2-011","type":"story","title":"US-011: Tool Type Definition System","description":"As an admin, I want to define tool types using Docker Compose templates so that new tools can be added without code changes.\n\n## Acceptance Criteria\n- [ ] Create ToolType model with fields: name, description, docker_compose_template, icon, category, default_env_vars, default_ports\n- [ ] Support template variables: {{REPO_PATH}}, {{WORKSPACE_DIR}}, {{USER_ID}}, {{PROJECT_ID}}, {{TOOL_ID}}\n- [ ] Seed database with 3 built-in tool types: code-server, jupyter-notebook, opencode\n- [ ] GET /tool-types endpoint listing all available tool types\n- [ ] GET /tool-types/{id} returning tool type details\n- [ ] Docker Compose templates validated on create/update\n- [ ] Tests for template validation and variable substitution\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":[]} -{"id":"phase2-012","type":"story","title":"US-012: Tool Instance Model & Database Schema","description":"As a developer, I want a database model for tool instances so that I can track running tools and their state.\n\n## Acceptance Criteria\n- [ ] Create ToolInstance model with fields: id, name, project_id, repo_id, tool_type_id, status, container_id, subdomain, ports, env_vars, created_at, started_at, stopped_at\n- [ ] Status enum: pending, building, running, stopped, error\n- [ ] Relationship: ToolInstance belongs to Project and GitRepository\n- [ ] Alembic migration for tool instance tables\n- [ ] ToolInstanceConfig model for per-instance config overrides\n- [ ] Tests for model relationships and status transitions\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-011"]} -{"id":"phase2-013","type":"story","title":"US-013: Docker Compose Template Engine","description":"As a developer, I want a template engine that renders Docker Compose files with project-specific values so that tools launch with correct configuration.\n\n## Acceptance Criteria\n- [ ] Implement template rendering engine (Jinja2 or string replacement)\n- [ ] Variable substitution: {{REPO_PATH}}, {{WORKSPACE_DIR}}, {{USER_ID}}, {{PROJECT_ID}}, {{TOOL_ID}}, {{SUBDOMAIN}}\n- [ ] Support environment variable injection from project/user config\n- [ ] Support port mapping configuration (host port allocation)\n- [ ] Support volume mounts (repo code, config files, persistent data)\n- [ ] Support network attachment (Traefik network)\n- [ ] Tests for template rendering with various inputs\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":1,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-011"]} -{"id":"phase2-014","type":"story","title":"US-014: Tool Spawning & Docker Integration","description":"As a user, I want to launch tools from my repositories so that I can start working immediately.\n\n## Acceptance Criteria\n- [ ] POST /tools endpoint to create and launch a tool instance\n- [ ] Accept parameters: name, project_id, repo_id, tool_type_id, env_vars (optional), config_overrides (optional)\n- [ ] Generate unique subdomain: {tool-name}-{tool-id}.hq.local\n- [ ] Render Docker Compose template with project values\n- [ ] Execute docker compose up -d to launch container\n- [ ] Store container_id and update status to running\n- [ ] Handle build errors and set status to error with logs\n- [ ] POST /tools/{id}/stop to stop container (docker compose stop)\n- [ ] POST /tools/{id}/start to start stopped container\n- [ ] DELETE /tools/{id} to stop and remove container + data\n- [ ] Tests mocking Docker compose commands\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-012","phase2-013"]} -{"id":"phase2-015","type":"story","title":"US-015: Traefik Route Generation","description":"As a user, I want tools accessible via clean URLs so that I can access them without remembering ports.\n\n## Acceptance Criteria\n- [ ] Auto-generate Traefik labels on tool containers:\n - traefik.enable=true\n - traefik.http.routers.{tool_id}.rule=Host({subdomain}.hq.local)\n - traefik.http.routers.{tool_id}.entrypoints=web\n - traefik.http.services.{tool_id}.loadbalancer.server.port={port}\n- [ ] Tools join Traefik Docker network for routing\n- [ ] GET /tools/{id}/url returning accessible URL\n- [ ] Handle subdomain collisions (append random suffix if needed)\n- [ ] Support HTTPS in production (websecure entrypoint)\n- [ ] Tests for label generation and URL construction\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]} -{"id":"phase2-016","type":"story","title":"US-016: Web-Based Terminal (xterm.js)","description":"As a user, I want a terminal in my browser to interact with running tools so that I don't need SSH access.\n\n## Acceptance Criteria\n- [ ] WebSocket endpoint /ws/terminal/{tool_id} for terminal sessions\n- [ ] Use docker exec to spawn shell in running container\n- [ ] Stream stdin/stdout/stderr via WebSocket\n- [ ] Terminal resize support (COLS, ROWS)\n- [ ] Session cleanup on disconnect\n- [ ] Authentication: only tool owner can access terminal\n- [ ] Frontend terminal component using xterm.js\n- [ ] Terminal connects to WebSocket with auth token\n- [ ] Support multiple terminal sessions per tool\n- [ ] Tests for WebSocket terminal lifecycle\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]} -{"id":"phase2-017","type":"story","title":"US-017: Tool Status Monitoring & Logs","description":"As a user, I want to see if my tools are running and view their logs so that I can debug issues.\n\n## Acceptance Criteria\n- [ ] GET /tools/{id}/status returning real-time container status\n- [ ] GET /tools/{id}/logs returning recent container logs (tail 100)\n- [ ] GET /tools/{id}/logs/stream WebSocket for live log streaming\n- [ ] Frontend tool dashboard showing:\n - Status indicator (running/stopped/error)\n - Uptime counter\n - Quick actions (start/stop/restart)\n - Log viewer with auto-scroll\n- [ ] Auto-refresh status every 5 seconds\n- [ ] Tests for status checking and log retrieval\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]} -{"id":"phase2-018","type":"story","title":"US-018: Frontend Tool Management UI","description":"As a user, I want a web interface to manage my tools so that I can launch, monitor, and access them easily.\n\n## Acceptance Criteria\n- [ ] Tools page listing all user's tool instances\n- [ ] Launch Tool button opening creation form\n- [ ] Form fields: name, project (dropdown), repository (dropdown), tool type (dropdown), environment variables (key-value), config overrides\n- [ ] Tool detail page showing:\n - Status and info\n - Open button (links to tool URL)\n - Terminal button (opens web terminal)\n - Logs panel\n - Settings (env vars, restart, delete)\n- [ ] Tool cards on dashboard showing quick stats\n- [ ] Empty state when no tools exist\n- [ ] Tests for tool CRUD operations in frontend\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":2,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-015","phase2-016","phase2-017"]} -{"id":"phase2-019","type":"story","title":"US-019: Tool Configuration & Environment Variables","description":"As a user, I want to configure tools with custom environment variables and settings so that they work for my specific needs.\n\n## Acceptance Criteria\n- [ ] Global tool config at user level (default env vars for all tools)\n- [ ] Project-level tool config (overrides global defaults)\n- [ ] Tool instance-level config (overrides project defaults)\n- [ ] PATCH /tools/{id}/config endpoint for updating config\n- [ ] Config inheritance: user defaults -> project overrides -> instance overrides\n- [ ] Frontend config editor with key-value pairs\n- [ ] Support for secret values (masked in UI, encrypted at rest)\n- [ ] Tests for config inheritance and override logic\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":3,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-014"]} -{"id":"phase2-020","type":"story","title":"US-020: Phase 2 Integration & Documentation","description":"As a developer, I want Phase 2 fully integrated with Phase 1 and documented so that the platform is cohesive.\n\n## Acceptance Criteria\n- [ ] Tool instances linked to projects and repositories (Phase 1 models)\n- [ ] SSH keys from Phase 1 available inside tool containers (mount ~/.ssh)\n- [ ] Git user config from Phase 1 applied to tool containers\n- [ ] Update API docs with all new endpoints\n- [ ] README section for tool configuration\n- [ ] Architecture Decision Record (ADR) for Docker Compose template approach\n- [ ] All quality gates passing\n- [ ] End-to-end test: create repo -> launch code-server -> access via URL -> open terminal\n\n## Quality Gates\n- pytest must pass\n- mypy . must pass\n- ruff check . must pass\n- npm run typecheck must pass\n- npm run lint must pass","status":"open","priority":3,"parent":"phase2-epic","external_ref":null,"dependencies":["phase2-015","phase2-016","phase2-017","phase2-018","phase2-019"]} diff --git a/.beads/config.yaml b/.beads/config.yaml deleted file mode 100644 index 232b151..0000000 --- a/.beads/config.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# Beads Configuration File -# This file configures default behavior for all bd commands in this repository -# All settings can also be set via environment variables (BD_* prefix) -# or overridden with command-line flags - -# Issue prefix for this repository (used by bd init) -# If not set, bd init will auto-detect from directory name -# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc. -# issue-prefix: "" - -# Use no-db mode: JSONL-only, no Dolt database -# When true, bd will use .beads/issues.jsonl as the source of truth -# no-db: false - -# Enable JSON output by default -# json: false - -# Feedback title formatting for mutating commands (create/update/close/dep/edit) -# 0 = hide titles, N > 0 = truncate to N characters -# output: -# title-length: 255 - -# Default actor for audit trails (overridden by BEADS_ACTOR or --actor) -# actor: "" - -# Export events (audit trail) to .beads/events.jsonl on each flush/sync -# When enabled, new events are appended incrementally using a high-water mark. -# Use 'bd export --events' to trigger manually regardless of this setting. -# events-export: false - -# Multi-repo configuration (experimental - bd-307) -# Allows hydrating from multiple repositories and routing writes to the correct database -# repos: -# primary: "." # Primary repo (where this database lives) -# additional: # Additional repos to hydrate from (read-only) -# - ~/beads-planning # Personal planning repo -# - ~/work-planning # Work planning repo - -# JSONL backup (periodic export for off-machine recovery) -# Auto-enabled when a git remote exists. Override explicitly: -# backup: -# enabled: false # Disable auto-backup entirely -# interval: 15m # Minimum time between auto-exports -# git-push: false # Disable git push (export locally only) -# git-repo: "" # Separate git repo for backups (default: project repo) - -# Integration settings (access with 'bd config get/set') -# These are stored in the database, not in this file: -# - jira.url -# - jira.project -# - linear.url -# - linear.api-key -# - github.org -# - github.repo diff --git a/.beads/hooks/post-checkout b/.beads/hooks/post-checkout deleted file mode 100755 index d485872..0000000 --- a/.beads/hooks/post-checkout +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# --- BEGIN BEADS INTEGRATION v1.0.3 --- -# This section is managed by beads. Do not remove these markers. -if command -v bd >/dev/null 2>&1; then - export BD_GIT_HOOK=1 - _bd_timeout=${BEADS_HOOK_TIMEOUT:-300} - if command -v timeout >/dev/null 2>&1; then - timeout "$_bd_timeout" bd hooks run post-checkout "$@" - _bd_exit=$? - if [ $_bd_exit -eq 124 ]; then - echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads" - _bd_exit=0 - fi - else - bd hooks run post-checkout "$@" - _bd_exit=$? - fi - if [ $_bd_exit -eq 3 ]; then - echo >&2 "beads: database not initialized — skipping hook 'post-checkout'" - _bd_exit=0 - fi - if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi -fi -# --- END BEADS INTEGRATION v1.0.3 --- diff --git a/.beads/hooks/post-merge b/.beads/hooks/post-merge deleted file mode 100755 index 5aa3315..0000000 --- a/.beads/hooks/post-merge +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# --- BEGIN BEADS INTEGRATION v1.0.3 --- -# This section is managed by beads. Do not remove these markers. -if command -v bd >/dev/null 2>&1; then - export BD_GIT_HOOK=1 - _bd_timeout=${BEADS_HOOK_TIMEOUT:-300} - if command -v timeout >/dev/null 2>&1; then - timeout "$_bd_timeout" bd hooks run post-merge "$@" - _bd_exit=$? - if [ $_bd_exit -eq 124 ]; then - echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads" - _bd_exit=0 - fi - else - bd hooks run post-merge "$@" - _bd_exit=$? - fi - if [ $_bd_exit -eq 3 ]; then - echo >&2 "beads: database not initialized — skipping hook 'post-merge'" - _bd_exit=0 - fi - if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi -fi -# --- END BEADS INTEGRATION v1.0.3 --- diff --git a/.beads/hooks/pre-commit b/.beads/hooks/pre-commit deleted file mode 100755 index d7ac3d9..0000000 --- a/.beads/hooks/pre-commit +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# --- BEGIN BEADS INTEGRATION v1.0.3 --- -# This section is managed by beads. Do not remove these markers. -if command -v bd >/dev/null 2>&1; then - export BD_GIT_HOOK=1 - _bd_timeout=${BEADS_HOOK_TIMEOUT:-300} - if command -v timeout >/dev/null 2>&1; then - timeout "$_bd_timeout" bd hooks run pre-commit "$@" - _bd_exit=$? - if [ $_bd_exit -eq 124 ]; then - echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads" - _bd_exit=0 - fi - else - bd hooks run pre-commit "$@" - _bd_exit=$? - fi - if [ $_bd_exit -eq 3 ]; then - echo >&2 "beads: database not initialized — skipping hook 'pre-commit'" - _bd_exit=0 - fi - if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi -fi -# --- END BEADS INTEGRATION v1.0.3 --- diff --git a/.beads/hooks/pre-push b/.beads/hooks/pre-push deleted file mode 100755 index 5af9e7b..0000000 --- a/.beads/hooks/pre-push +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# --- BEGIN BEADS INTEGRATION v1.0.3 --- -# This section is managed by beads. Do not remove these markers. -if command -v bd >/dev/null 2>&1; then - export BD_GIT_HOOK=1 - _bd_timeout=${BEADS_HOOK_TIMEOUT:-300} - if command -v timeout >/dev/null 2>&1; then - timeout "$_bd_timeout" bd hooks run pre-push "$@" - _bd_exit=$? - if [ $_bd_exit -eq 124 ]; then - echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads" - _bd_exit=0 - fi - else - bd hooks run pre-push "$@" - _bd_exit=$? - fi - if [ $_bd_exit -eq 3 ]; then - echo >&2 "beads: database not initialized — skipping hook 'pre-push'" - _bd_exit=0 - fi - if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi -fi -# --- END BEADS INTEGRATION v1.0.3 --- diff --git a/.beads/hooks/prepare-commit-msg b/.beads/hooks/prepare-commit-msg deleted file mode 100755 index f0aec3c..0000000 --- a/.beads/hooks/prepare-commit-msg +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# --- BEGIN BEADS INTEGRATION v1.0.3 --- -# This section is managed by beads. Do not remove these markers. -if command -v bd >/dev/null 2>&1; then - export BD_GIT_HOOK=1 - _bd_timeout=${BEADS_HOOK_TIMEOUT:-300} - if command -v timeout >/dev/null 2>&1; then - timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@" - _bd_exit=$? - if [ $_bd_exit -eq 124 ]; then - echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads" - _bd_exit=0 - fi - else - bd hooks run prepare-commit-msg "$@" - _bd_exit=$? - fi - if [ $_bd_exit -eq 3 ]; then - echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'" - _bd_exit=0 - fi - if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi -fi -# --- END BEADS INTEGRATION v1.0.3 --- diff --git a/.beads/metadata.json b/.beads/metadata.json deleted file mode 100644 index 4831125..0000000 --- a/.beads/metadata.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "database": "dolt", - "backend": "dolt", - "dolt_mode": "embedded", - "dolt_database": "headquarter", - "project_id": "d9aa6d40-ce59-4c2c-8cea-f33879137a56" -} \ No newline at end of file diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 963a538..0000000 --- a/.claude/settings.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "hooks": { - "PreCompact": [ - { - "hooks": [ - { - "command": "bd prime", - "type": "command" - } - ], - "matcher": "" - } - ], - "SessionStart": [ - { - "hooks": [ - { - "command": "bd prime", - "type": "command" - } - ], - "matcher": "" - } - ] - } -} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 7875149..0000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.py] -indent_size = 4 - -[Makefile] -indent_style = tab diff --git a/.env.example b/.env.example index 253ed0e..3aff032 100644 --- a/.env.example +++ b/.env.example @@ -1,42 +1,24 @@ -# App identity -APP_NAME=Headquarter -ROOT_DOMAIN=localhost -TOOL_DOMAIN=tools.localhost - -# API / Web URLs -API_URL=http://localhost:8000 -WEB_URL=http://localhost:5173 -CORS_ORIGINS=http://localhost:5173 - -# Database (local development) -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres +# Database Configuration +POSTGRES_USER=headquarter +POSTGRES_PASSWORD=change-me-in-production POSTGRES_DB=headquarter -# DATABASE_URL uses a literal value because Pydantic Settings does not expand -# shell-style variable interpolation from .env files. -DATABASE_URL=postgresql://postgres:postgres@localhost:5432/headquarter -# Authentik OIDC placeholders (wire in FN-004) -AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/headquarter/ -AUTHENTIK_CLIENT_ID=your-client-id -AUTHENTIK_CLIENT_SECRET=your-client-secret +# Redis Configuration +REDIS_URL=redis://redis:6379/0 -# Traefik / deployment placeholders (wire in FN-006) -TRAEFIK_NETWORK=traefik -TRAEFIK_ENTRYPOINT=websecure -TRAEFIK_CERT_RESOLVER=letsencrypt -TRAEFIK_LOG_LEVEL=INFO -TRAEFIK_ACME_EMAIL=admin@example.com -TOOL_SUBDOMAIN_PATTERN={tool}-{project}-{user}.tools.localhost +# JWT Configuration +JWT_SECRET=change-me-in-production +JWT_ALGORITHM=HS256 +JWT_EXPIRATION_HOURS=24 -# Frontend build-time variables (passed to web container) +# Application Configuration +APP_ENV=development +DEBUG=true +LOG_LEVEL=info +REPO_BASE_PATH=/data/repos + +# Frontend Configuration VITE_API_URL=http://localhost:8000 -VITE_OIDC_ISSUER=https://auth.example.com/application/o/headquarter/ -VITE_OIDC_CLIENT_ID=your-client-id -VITE_OIDC_REDIRECT_URI=https://headquarter.commumedia.org/callback -# Secrets (generate strong random values for production) -SECRET_ENCRYPTION_KEY=change-me-in-production - -# Auth dev bypass (local development only — NEVER enable in production) -AUTH_DEV_BYPASS=false +# Docker Configuration +COMPOSE_PROJECT_NAME=headquarter diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 543516f..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - web-ci: - name: Web CI - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9 - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Lint - run: pnpm --filter @headquarter/web lint - - - name: Typecheck - run: pnpm --filter @headquarter/web typecheck - - - name: Test - run: pnpm --filter @headquarter/web test - - api-ci: - name: API CI - runs-on: ubuntu-latest - services: - postgres: - image: postgres:16 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: headquarter_test - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install API dev dependencies - working-directory: apps/api - run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" - - - name: Ruff check - working-directory: apps/api - run: ruff check app/ tests/ - - - name: Mypy - working-directory: apps/api - run: mypy app/ tests/ - - - name: Pytest - working-directory: apps/api - env: - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/headquarter_test - run: pytest diff --git a/.opencode/commands/opsx-apply.md b/.opencode/commands/opsx-apply.md new file mode 100644 index 0000000..16d2ef3 --- /dev/null +++ b/.opencode/commands/opsx-apply.md @@ -0,0 +1,149 @@ +--- +description: Implement tasks from an OpenSpec change (Experimental) +--- + +Implement tasks from an OpenSpec change. + +**Input**: Optionally specify a change name (e.g., `/opsx-apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Select the change** + + If a name is provided, use it. Otherwise: + - Infer from conversation context if the user mentioned a change + - Auto-select if only one active change exists + - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select + + Always announce: "Using change: " and how to override (e.g., `/opsx-apply `). + +2. **Check status to understand the schema** + ```bash + openspec status --change "" --json + ``` + Parse the JSON to understand: + - `schemaName`: The workflow being used (e.g., "spec-driven") + - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) + +3. **Get apply instructions** + + ```bash + openspec instructions apply --change "" --json + ``` + + This returns: + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema) + - Progress (total, complete, remaining) + - Task list with status + - Dynamic instruction based on current state + + **Handle states:** + - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx-continue` + - If `state: "all_done"`: congratulate, suggest archive + - Otherwise: proceed to implementation + +4. **Read context files** + + Read every file path listed under `contextFiles` from the apply instructions output. + The files depend on the schema being used: + - **spec-driven**: proposal, specs, design, tasks + - Other schemas: follow the contextFiles from CLI output + +5. **Show current progress** + + Display: + - Schema being used + - Progress: "N/M tasks complete" + - Remaining tasks overview + - Dynamic instruction from CLI + +6. **Implement tasks (loop until done or blocked)** + + For each pending task: + - Show which task is being worked on + - Make the code changes required + - Keep changes minimal and focused + - Mark task complete in the tasks file: `- [ ]` → `- [x]` + - Continue to next task + + **Pause if:** + - Task is unclear → ask for clarification + - Implementation reveals a design issue → suggest updating artifacts + - Error or blocker encountered → report and wait for guidance + - User interrupts + +7. **On completion or pause, show status** + + Display: + - Tasks completed this session + - Overall progress: "N/M tasks complete" + - If all done: suggest archive + - If paused: explain why and wait for guidance + +**Output During Implementation** + +``` +## Implementing: (schema: ) + +Working on task 3/7: +[...implementation happening...] +✓ Task complete + +Working on task 4/7: +[...implementation happening...] +✓ Task complete +``` + +**Output On Completion** + +``` +## Implementation Complete + +**Change:** +**Schema:** +**Progress:** 7/7 tasks complete ✓ + +### Completed This Session +- [x] Task 1 +- [x] Task 2 +... + +All tasks complete! You can archive this change with `/opsx-archive`. +``` + +**Output On Pause (Issue Encountered)** + +``` +## Implementation Paused + +**Change:** +**Schema:** +**Progress:** 4/7 tasks complete + +### Issue Encountered + + +**Options:** +1.