{"owner":"getarcaneapp","repo":"arcane","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# Arcane Agent Guide\n\nAll AI-assisted work must follow [AI_POLICY.md](./AI_POLICY.md). Keep changes focused,\nverify them locally, and disclose AI assistance when contributing.\n\nArcane is a Docker management platform with a Go backend, SvelteKit frontend,\nheadless agent modes, and a Cobra CLI.\n\n## Non-negotiable rules\n\n- Update existing code in place. Search before adding functions, services, wrappers,\n  API clients, components, or utilities.\n- Never add stubs, shims, pass-through helpers, or duplicate implementations.\n- Call existing `pkg/` helpers directly instead of wrapping them.\n- Add new code only for genuinely new behavior and integrate it with the owning domain.\n- Keep comments short. If code needs a paragraph to explain its structure, simplify it.\n- Never run state-changing Git commands. Do not stage, commit, push, tag, stash,\n  create branches, or create worktrees.\n- Always use the `golang-master` skill when writing Go.\n- Name every unexported Go function with an `Internal` suffix.\n- Put public/shared Go types in the top-level `types/` module.\n- Put reusable helper utilities under `backend/pkg/utils/` in the appropriate package.\n- After any change, run `just format all`, then `just lint all`, and fix every issue.\n  Never revert formatter output.\n\n## Repository architecture\n\nThe Go workspace contains three modules:\n\n```text\nbackend/   Go application, HTTP API, domain logic, jobs, and embedded frontend\ncli/       Cobra CLI and its API client\ntypes/     Public domain and API contracts shared by backend and CLI\n```\n\nThe frontend lives in `frontend/`. End-to-end tests live in `tests/`.\n\n### Backend\n\nThe backend uses domain-oriented vertical slices:\n\n```text\nbackend/\n├── cmd/                 process entrypoint\n├── api/                 API assembly and exceptional HTTP/stream/WebSocket routes\n├── internal/\n│   ├── <domain>/        domain module, handler, service, and related files\n│   ├── bootstrap/       application lifecycle, router, jobs, and startup wiring\n│   ├── di/              Fx dependency graph and providers\n│   ├── config/          environment configuration\n│   ├── database/        database setup and migrations\n│   ├── middleware/      authentication, authorization, and environment proxying\n│   └── models/          private GORM persistence models\n├── pkg/                 reusable infrastructure and domain-independent libraries\n├── resources/           migrations, email templates, and runtime assets\n└── frontend/            embedded frontend build\n```\n\nMost domains under `backend/internal/<domain>/` follow this shape:\n\n- `module.go` constructs the domain and exposes `Service()` or `Handler()` only when\n  another domain needs them.\n- `handler.go` owns Huma input/output types, route registration, and thin handlers.\n- `service.go` and focused sibling files own business logic.\n- Tests stay beside the code they cover.\n\nWire dependencies in `internal/di`; keep startup order and lifecycle hooks in\n`internal/bootstrap`. Do not turn `api/` back into a global handlers directory or\nrecreate a global `internal/services` layer.\n\nUse Echo v5 as the router and Huma v2 for typed REST/OpenAPI operations. Register\npermissioned endpoints with `middleware.RegisterWithPermission`. Direct Echo routes\nare reserved for WebSockets, streams, diagnostics, webhooks, Playwright support,\nthe environment proxy, and embedded frontend delivery.\n\nHandlers translate typed HTTP data and call services. They do not contain business\nlogic. Services receive dependencies through constructors/Fx. Use `slog` for\nstructured logging and the existing `emperror.dev/errors` and `internal/common`\npatterns for wrapped or semantic errors.\n\nBefore adding backend logic, search the owning domain plus:\n\n- `backend/pkg/dockerutil` for Docker names, labels, clients, logs, and stream helpers.\n- `backend/pkg/projects` for Compose parsing, discovery, and image references.\n- `backend/pkg/pagination` for in-memory and database pagination.\n- `backend/pkg/libarcane` for reusable Arcane engines and transport behavior.\n- `backend/pkg/utils` for shared infrastructure utilities.\n\nPersistence models embed `models.BaseModel`. Use existing GORM model helpers and\n`Preload` relationships where appropriate; do not expose persistence models as API\ncontracts.\n\n### Frontend\n\nThe frontend is SvelteKit v3 on Svelte 5. Configuration lives in\n`frontend/vite.config.ts`.\n\n```text\nfrontend/src/\n├── routes/              SvelteKit pages and layouts\n└── lib/\n    ├── components/      shared UI components\n    ├── config/          navigation and access-surface configuration\n    ├── services/        API clients extending BaseAPIService\n    ├── stores/          rune-based application state\n    ├── types/           frontend-only TypeScript types\n    └── utils/           frontend utilities\n```\n\n- Use Svelte 5 runes: `$props`, `$state`, `$derived`, and `$effect`.\n- Do not use `export let`, `$:`, `on:event`, `$$props`, `$$restProps`, or legacy slots.\n- Extend `BaseAPIService`; reuse existing services and query/mutation patterns.\n- Use precise TypeScript types. Do not introduce `any`.\n- Reuse shared components before creating page-local variants.\n- Put every rendered string behind Paraglide messages.\n- Reuse a matching key from `frontend/messages/en.json` before adding one.\n- Add new keys only to `en.json`; Crowdin manages every other locale.\n\n### Multi-environment and authorization\n\n- Environment ID `\"0\"` is the local Docker environment.\n- Environment-scoped API paths use `/environments/{id}/...`.\n- Await `environmentStore.ready` or `getCurrentEnvironmentId()` before requests.\n- Redirect environment-specific detail pages when the selected environment changes.\n- Backend permission middleware is authoritative; frontend gates are UX only.\n- Keep the permission catalog, access-surface registry, and frontend navigation gates\n  as separate layers.\n- Determine global admin status from `PermissionSet.IsGlobalAdmin()` or the user DTO's\n  `isGlobalAdmin`; never infer it from a role ID.\n\n### Runtime modes and jobs\n\n- Manager mode serves the UI and manages environments.\n- Direct agent mode uses `AGENT_MODE=true` and accepts manager connections.\n- Edge agent mode uses `EDGE_AGENT=true` with `MANAGER_API_URL` and dials the manager.\n- Background jobs implement the scheduler job contract and are wired through\n  `internal/di` and registered in `internal/bootstrap/jobs_bootstrap.go`.\n\n## Validation\n\nUse the narrowest relevant test first, then the repository gates:\n\n```bash\njust format all\njust lint all\njust test backend|cli|types|e2e|all\n```\n\nFor AI-assisted code contributions, also run the development environment and manually\nexercise the changed frontend and backend behavior as required by `AI_POLICY.md`.\n"},"files":{"AGENTS.md":"# Arcane Agent Guide\n\nAll AI-assisted work must follow [AI_POLICY.md](./AI_POLICY.md). Keep changes focused,\nverify them locally, and disclose AI assistance when contributing.\n\nArcane is a Docker management platform with a Go backend, SvelteKit frontend,\nheadless agent modes, and a Cobra CLI.\n\n## Non-negotiable rules\n\n- Update existing code in place. Search before adding functions, services, wrappers,\n  API clients, components, or utilities.\n- Never add stubs, shims, pass-through helpers, or duplicate implementations.\n- Call existing `pkg/` helpers directly instead of wrapping them.\n- Add new code only for genuinely new behavior and integrate it with the owning domain.\n- Keep comments short. If code needs a paragraph to explain its structure, simplify it.\n- Never run state-changing Git commands. Do not stage, commit, push, tag, stash,\n  create branches, or create worktrees.\n- Always use the `golang-master` skill when writing Go.\n- Name every unexported Go function with an `Internal` suffix.\n- Put public/shared Go types in the top-level `types/` module.\n- Put reusable helper utilities under `backend/pkg/utils/` in the appropriate package.\n- After any change, run `just format all`, then `just lint all`, and fix every issue.\n  Never revert formatter output.\n\n## Repository architecture\n\nThe Go workspace contains three modules:\n\n```text\nbackend/   Go application, HTTP API, domain logic, jobs, and embedded frontend\ncli/       Cobra CLI and its API client\ntypes/     Public domain and API contracts shared by backend and CLI\n```\n\nThe frontend lives in `frontend/`. End-to-end tests live in `tests/`.\n\n### Backend\n\nThe backend uses domain-oriented vertical slices:\n\n```text\nbackend/\n├── cmd/                 process entrypoint\n├── api/                 API assembly and exceptional HTTP/stream/WebSocket routes\n├── internal/\n│   ├── <domain>/        domain module, handler, service, and related files\n│   ├── bootstrap/       application lifecycle, router, jobs, and startup wiring\n│   ├── di/              Fx dependency graph and providers\n│   ├── config/          environment configuration\n│   ├── database/        database setup and migrations\n│   ├── middleware/      authentication, authorization, and environment proxying\n│   └── models/          private GORM persistence models\n├── pkg/                 reusable infrastructure and domain-independent libraries\n├── resources/           migrations, email templates, and runtime assets\n└── frontend/            embedded frontend build\n```\n\nMost domains under `backend/internal/<domain>/` follow this shape:\n\n- `module.go` constructs the domain and exposes `Service()` or `Handler()` only when\n  another domain needs them.\n- `handler.go` owns Huma input/output types, route registration, and thin handlers.\n- `service.go` and focused sibling files own business logic.\n- Tests stay beside the code they cover.\n\nWire dependencies in `internal/di`; keep startup order and lifecycle hooks in\n`internal/bootstrap`. Do not turn `api/` back into a global handlers directory or\nrecreate a global `internal/services` layer.\n\nUse Echo v5 as the router and Huma v2 for typed REST/OpenAPI operations. Register\npermissioned endpoints with `middleware.RegisterWithPermission`. Direct Echo routes\nare reserved for WebSockets, streams, diagnostics, webhooks, Playwright support,\nthe environment proxy, and embedded frontend delivery.\n\nHandlers translate typed HTTP data and call services. They do not contain business\nlogic. Services receive dependencies through constructors/Fx. Use `slog` for\nstructured logging and the existing `emperror.dev/errors` and `internal/common`\npatterns for wrapped or semantic errors.\n\nBefore adding backend logic, search the owning domain plus:\n\n- `backend/pkg/dockerutil` for Docker names, labels, clients, logs, and stream helpers.\n- `backend/pkg/projects` for Compose parsing, discovery, and image references.\n- `backend/pkg/pagination` for in-memory and database pagination.\n- `backend/pkg/libarcane` for reusable Arcane engines and transport behavior.\n- `backend/pkg/utils` for shared infrastructure utilities.\n\nPersistence models embed `models.BaseModel`. Use existing GORM model helpers and\n`Preload` relationships where appropriate; do not expose persistence models as API\ncontracts.\n\n### Frontend\n\nThe frontend is SvelteKit v3 on Svelte 5. Configuration lives in\n`frontend/vite.config.ts`.\n\n```text\nfrontend/src/\n├── routes/              SvelteKit pages and layouts\n└── lib/\n    ├── components/      shared UI components\n    ├── config/          navigation and access-surface configuration\n    ├── services/        API clients extending BaseAPIService\n    ├── stores/          rune-based application state\n    ├── types/           frontend-only TypeScript types\n    └── utils/           frontend utilities\n```\n\n- Use Svelte 5 runes: `$props`, `$state`, `$derived`, and `$effect`.\n- Do not use `export let`, `$:`, `on:event`, `$$props`, `$$restProps`, or legacy slots.\n- Extend `BaseAPIService`; reuse existing services and query/mutation patterns.\n- Use precise TypeScript types. Do not introduce `any`.\n- Reuse shared components before creating page-local variants.\n- Put every rendered string behind Paraglide messages.\n- Reuse a matching key from `frontend/messages/en.json` before adding one.\n- Add new keys only to `en.json`; Crowdin manages every other locale.\n\n### Multi-environment and authorization\n\n- Environment ID `\"0\"` is the local Docker environment.\n- Environment-scoped API paths use `/environments/{id}/...`.\n- Await `environmentStore.ready` or `getCurrentEnvironmentId()` before requests.\n- Redirect environment-specific detail pages when the selected environment changes.\n- Backend permission middleware is authoritative; frontend gates are UX only.\n- Keep the permission catalog, access-surface registry, and frontend navigation gates\n  as separate layers.\n- Determine global admin status from `PermissionSet.IsGlobalAdmin()` or the user DTO's\n  `isGlobalAdmin`; never infer it from a role ID.\n\n### Runtime modes and jobs\n\n- Manager mode serves the UI and manages environments.\n- Direct agent mode uses `AGENT_MODE=true` and accepts manager connections.\n- Edge agent mode uses `EDGE_AGENT=true` with `MANAGER_API_URL` and dials the manager.\n- Background jobs implement the scheduler job contract and are wired through\n  `internal/di` and registered in `internal/bootstrap/jobs_bootstrap.go`.\n\n## Validation\n\nUse the narrowest relevant test first, then the repository gates:\n\n```bash\njust format all\njust lint all\njust test backend|cli|types|e2e|all\n```\n\nFor AI-assisted code contributions, also run the development environment and manually\nexercise the changed frontend and backend behavior as required by `AI_POLICY.md`.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Arcane Agent Guide\n\nAll AI-assisted work must follow [AI_POLICY.md](./AI_POLICY.md). Keep changes focused,\nverify them locally, and disclose AI assistance when contributing.\n\nArcane is a Docker management platform with a Go backend, SvelteKit frontend,\nheadless agent modes, and a Cobra CLI.\n\n## Non-negotiable rules\n\n- Update existing code in place. Search before adding functions, services, wrappers,\n  API clients, components, or utilities.\n- Never add stubs, shims, pass-through helpers, or duplicate implementations.\n- Call existing `pkg/` helpers directly instead of wrapping them.\n- Add new code only for genuinely new behavior and integrate it with the owning domain.\n- Keep comments short. If code needs a paragraph to explain its structure, simplify it.\n- Never run state-changing Git commands. Do not stage, commit, push, tag, stash,\n  create branches, or create worktrees.\n- Always use the `golang-master` skill when writing Go.\n- Name every unexported Go function with an `Internal` suffix.\n- Put public/shared Go types in the top-level `types/` module.\n- Put reusable helper utilities under `backend/pkg/utils/` in the appropriate package.\n- After any change, run `just format all`, then `just lint all`, and fix every issue.\n  Never revert formatter output.\n\n## Repository architecture\n\nThe Go workspace contains three modules:\n\n```text\nbackend/   Go application, HTTP API, domain logic, jobs, and embedded frontend\ncli/       Cobra CLI and its API client\ntypes/     Public domain and API contracts shared by backend and CLI\n```\n\nThe frontend lives in `frontend/`. End-to-end tests live in `tests/`.\n\n### Backend\n\nThe backend uses domain-oriented vertical slices:\n\n```text\nbackend/\n├── cmd/                 process entrypoint\n├── api/                 API assembly and exceptional HTTP/stream/WebSocket routes\n├── internal/\n│   ├── <domain>/        domain module, handler, service, and related files\n│   ├── bootstrap/       application lifecycle, router, jobs, and startup wiring\n│   ├── di/              Fx dependency graph and providers\n│   ├── config/          environment configuration\n│   ├── database/        database setup and migrations\n│   ├── middleware/      authentication, authorization, and environment proxying\n│   └── models/          private GORM persistence models\n├── pkg/                 reusable infrastructure and domain-independent libraries\n├── resources/           migrations, email templates, and runtime assets\n└── frontend/            embedded frontend build\n```\n\nMost domains under `backend/internal/<domain>/` follow this shape:\n\n- `module.go` constructs the domain and exposes `Service()` or `Handler()` only when\n  another domain needs them.\n- `handler.go` owns Huma input/output types, route registration, and thin handlers.\n- `service.go` and focused sibling files own business logic.\n- Tests stay beside the code they cover.\n\nWire dependencies in `internal/di`; keep startup order and lifecycle hooks in\n`internal/bootstrap`. Do not turn `api/` back into a global handlers directory or\nrecreate a global `internal/services` layer.\n\nUse Echo v5 as the router and Huma v2 for typed REST/OpenAPI operations. Register\npermissioned endpoints with `middleware.RegisterWithPermission`. Direct Echo routes\nare reserved for WebSockets, streams, diagnostics, webhooks, Playwright support,\nthe environment proxy, and embedded frontend delivery.\n\nHandlers translate typed HTTP data and call services. They do not contain business\nlogic. Services receive dependencies through constructors/Fx. Use `slog` for\nstructured logging and the existing `emperror.dev/errors` and `internal/common`\npatterns for wrapped or semantic errors.\n\nBefore adding backend logic, search the owning domain plus:\n\n- `backend/pkg/dockerutil` for Docker names, labels, clients, logs, and stream helpers.\n- `backend/pkg/projects` for Compose parsing, discovery, and image references.\n- `backend/pkg/pagination` for in-memory and database pagination.\n- `backend/pkg/libarcane` for reusable Arcane engines and transport behavior.\n- `backend/pkg/utils` for shared infrastructure utilities.\n\nPersistence models embed `models.BaseModel`. Use existing GORM model helpers and\n`Preload` relationships where appropriate; do not expose persistence models as API\ncontracts.\n\n### Frontend\n\nThe frontend is SvelteKit v3 on Svelte 5. Configuration lives in\n`frontend/vite.config.ts`.\n\n```text\nfrontend/src/\n├── routes/              SvelteKit pages and layouts\n└── lib/\n    ├── components/      shared UI components\n    ├── config/          navigation and access-surface configuration\n    ├── services/        API clients extending BaseAPIService\n    ├── stores/          rune-based application state\n    ├── types/           frontend-only TypeScript types\n    └── utils/           frontend utilities\n```\n\n- Use Svelte 5 runes: `$props`, `$state`, `$derived`, and `$effect`.\n- Do not use `export let`, `$:`, `on:event`, `$$props`, `$$restProps`, or legacy slots.\n- Extend `BaseAPIService`; reuse existing services and query/mutation patterns.\n- Use precise TypeScript types. Do not introduce `any`.\n- Reuse shared components before creating page-local variants.\n- Put every rendered string behind Paraglide messages.\n- Reuse a matching key from `frontend/messages/en.json` before adding one.\n- Add new keys only to `en.json`; Crowdin manages every other locale.\n\n### Multi-environment and authorization\n\n- Environment ID `\"0\"` is the local Docker environment.\n- Environment-scoped API paths use `/environments/{id}/...`.\n- Await `environmentStore.ready` or `getCurrentEnvironmentId()` before requests.\n- Redirect environment-specific detail pages when the selected environment changes.\n- Backend permission middleware is authoritative; frontend gates are UX only.\n- Keep the permission catalog, access-surface registry, and frontend navigation gates\n  as separate layers.\n- Determine global admin status from `PermissionSet.IsGlobalAdmin()` or the user DTO's\n  `isGlobalAdmin`; never infer it from a role ID.\n\n### Runtime modes and jobs\n\n- Manager mode serves the UI and manages environments.\n- Direct agent mode uses `AGENT_MODE=true` and accepts manager connections.\n- Edge agent mode uses `EDGE_AGENT=true` with `MANAGER_API_URL` and dials the manager.\n- Background jobs implement the scheduler job contract and are wired through\n  `internal/di` and registered in `internal/bootstrap/jobs_bootstrap.go`.\n\n## Validation\n\nUse the narrowest relevant test first, then the repository gates:\n\n```bash\njust format all\njust lint all\njust test backend|cli|types|e2e|all\n```\n\nFor AI-assisted code contributions, also run the development environment and manually\nexercise the changed frontend and backend behavior as required by `AI_POLICY.md`.\n","category":"root","tokens":1684}]}