# Repository Guidelines ## Scope and Structure This repository is the experimental TJWater supply Agent service. Keep drainage data, workflows, layer IDs, and terminology in the drainage repositories. Read [README.md](README.md) for setup, configuration, and operational behavior. - `src/server.ts` assembles dependencies and starts the service. - `src/routes/` owns HTTP/SSE wiring; keep orchestration thin. - `src/context/` owns local and Server-verified request context. - `src/product/` owns typed TJWater Server adapters and business contracts. - `src/frontendAction/` owns controlled browser actions and their receipts. - `src/uiEnvelope/` owns the `agent-ui@1` compatibility protocol and registry. - `src/runtime/` owns OpenCode lifecycle, readiness, and workspace binding. - `src/sandbox/` and `scripts/landlock_sandbox.py` own Shell enforcement. - `src/sessions/`, `src/results/`, `src/memory/`, and `src/learning/` retain their respective persistence responsibilities. - `.opencode/` contains trusted service instructions, plugins, and tools. - `.opencode/agent-plugin.json` describes agents, plugins, Skill storage, and MCP configuration sources; `.opencode/README.md` explains their management. - `tests/` contains focused tests and opt-in native integration scripts. Use TypeScript ESM, two-space indentation, kebab-case module filenames, and explicit types at public boundaries. Preserve established service patterns before adding new abstractions. Backend access must use typed tools/adapters; do not introduce `cli/`, `tjwater_cli`, or a free-form business command bridge. The existing approved sandbox Shell is the only local command execution path. ## Model Configuration `agent-models.json` is the single model configuration source. An explicit `AGENT_MODEL_CONFIG_PATH` selects a complete replacement; relative paths resolve from the process working directory. `agent-models.local.json` is ignored by Git and the Docker build. - Define provider IDs, `api_url`, API key references, models, aliases, capabilities, limits, and chat/task/learning role defaults in that file. - Generate OpenCode definitions and the public chat model menu from it through `src/chat/modelConfig.ts` and `src/runtime/opencode2-config.ts`. - Do not add independent model defaults in `opencode.json`, agent frontmatter, routes, learning code, or environment variables. Legacy `OPENCODE_MODEL`, `OPERATIONAL_TASK_MODEL`, and `OPENCODE_MODEL_OPTIONS` no longer select models. - Use `model_id` when the Agent-facing name differs from the upstream name; preserve existing public references when correcting upstream aliases. - Keep real API keys in ignored `.local.env` or deployment environment variables; use `{env:NAME}` references in model files. Existing system environment values take precedence over `.local.env`. - Never return provider URLs, keys, headers, or effective credential settings in model menus, validation reports, status endpoints, or logs. After model/provider changes, run `bun run check:models`. It launches an isolated OpenCode and validates all non-disabled models, including hidden task/learning models, against effective native definitions and upstream `/models` inventories. A self-declared `model.list` entry alone is not validation. `disabled` skips a model; `selectable: false` only hides it from the chat menu and does not skip it. Do not use paid inference as the default configuration check. The checker lives in `.opencode/model-check.ts`, with shared report/target types in `src/runtime/model-check.ts` and the command in `scripts/check-models.ts`. Preserve safe errors and cancellation. SIGINT/SIGTERM must abort model checking, wait for its owned OpenCode process to exit, and clean its temporary directories. Unsupported catalogs, absent upstream names, authentication failures, and invalid inventories must fail validation. Changes require an Agent restart; client mode also requires synchronized external OpenCode configuration and plugins. ## Runtime and Security Production chat requests require Bearer authorization and `X-Project-Id`, verified by TJWater Server. Preserve actor/project/user ownership checks on session create, read, actions, and MCP status. Development-only local context does not grant business-data access. Never accept a tool-supplied identity, project scope, authorization header, or arbitrary Server URL. Complete the OS sandbox probe, OpenCode health check, warmup session, business tool discovery, enabled-model validation, workspace-root check, and MCP configuration check before HTTP starts listening. A failure must fail startup. Preserve `/health` fields `ready`, `warmed_up`, and `sandbox`. Use the V2 SDK and trusted plugin registration. A cold Location may need plugin initialization before its tool/model catalog is usable. Verify actual tool IDs; a version string or MCP connection status alone does not prove availability. Keep native call IDs and the existing frontend SSE contracts. Client mode requires the same stable `AGENT_INTERNAL_TOKEN` in both processes, the external OpenCode server password, and trusted assets loaded through `serviceOpencodeConfig`. Its absolute `TJWATER_AGENT_WORKSPACE_ROOT` must match the Agent workspace root. Prefer `bun run start:integration:isolated` when an existing user service must remain available. Stop only processes started for the current task; do not terminate unrelated services. Preserve static sensitive-path denials in `opencode.json`, explicit approval for Shell/file edits, and disabled subagents. Do not replace enforcement with prompt instructions. The Shell replacement must retain Landlock/seccomp, credential isolation, cancellation, process-group cleanup, and denied alternate host Shell entry points. Code Mode must not bypass these controls. ## Workspaces and Persistence `CONVERSATION_WORKSPACE_ROOT` defaults to `.agent-workspaces/`, separate from protected `data/` and `logs/`. `src/runtime/conversationWorkspace.ts` creates one `conversation-` per native session, with writable `files/`, `tmp/`, and `.cache/`; the location root is read-only and Shell starts in `files/`. Keep canonical-path and symlink checks, per-session access restrictions, native session directory bindings, and empty independent workspaces for new branches. Do not copy source code, credentials, or other sessions into a workspace. Workspaces contain persistent session files. They currently have no expiration cleanup, and deleting chat metadata does not remove their directories. Do not clean them as build artifacts or describe them as automatically disposable. Startup probes, warmup, and failed creation clean their own temporary workspaces. Changing the root requires preserving directory bindings and associated native session data; do not silently move or delete existing user files. Deployment must preserve the workspace, Agent data, Skill files, and OpenCode session database. Mounting only `/app/data` does not preserve session files. Result-reference TTL cleanup is separate from workspace retention. ## MCP and Business Boundaries Keep the `.opencode/agent-plugin.json` descriptor and package descriptions aligned with actual IDs and paths when agent/plugin assets change. The descriptor is a documentation index, not a runtime configuration file or native OpenCode plugin manifest. Do not duplicate model definitions, Skill inventories, MCP connections, or credentials in it. Use the established configuration builder and source files. Skill storage is shared by the deployment instance; do not describe it as isolated per user or project, and preserve the existing validated persistence workflow. Configure external MCP only through administrator-owned `mcp.servers` in `opencode.json` or `OPENCODE_CONFIG_CONTENT`; server names use the `mcp_` prefix. Preserve exact read-only tool allow rules, interactive approval outside that allowlist, read-only background task access, and disabled MCP in learning review. Broad wildcard allows and server `readOnlyHint` values are not read-only grants. Apply the same policy to Code Mode and generic MCP resource access. Local stdio MCP is a trusted host process, not a sandbox Shell process. Preserve its explicit environment filtering and never forward Agent/OpenCode credentials. Return only sanitized server status and actual tool IDs to the browser. Keep business state authoritative in Server. Background execution uses persisted `task_id`, `run_id`, and `execution_request_id`, with explicit claim, heartbeat, and complete/fail transitions. Plans, reports, browser receipts, and final text are distinct from execution completion. See [docs/execution-plan.md](docs/execution-plan.md) and [docs/agent-ui-protocol.md](docs/agent-ui-protocol.md). ## Commands and Verification Run commands from this repository with Bun: ```bash bun install bun run dev bun run start bun run check bun run check:models bun run start:integration:isolated ``` `bun run check` type-checks both the service and `.opencode`; this repository has no separate lint command. Run focused tests for the changed behavior. For model and readiness changes, the relevant suite is: ```bash bun test tests/chat/models.test.ts tests/opencode/modelCheck.test.ts tests/runtime/opencode.test.ts tests/runtime/modelCheckCommand.test.ts tests/frontendAction/callIdPlugin.test.ts ``` Do not over-test reversible low-impact edits. Documentation-only changes need local link/path and command validation plus `git diff --check`, without starting services or calling providers. Tests must not depend on mutable `data/` files. Use opt-in native smoke scripts only when actual integration behavior needs verification; configuration/catalog checks must not invoke model inference. ## Repository Hygiene and Delivery Never commit secrets, private environment files, generated runtime data, logs, dependencies, `.agent-workspaces/`, session dumps, or result references. Avoid printing private configuration contents while inspecting a workspace. Preserve unrelated dirty and untracked work. Keep `README.md` useful to people: configuration locations, runnable setup steps, model checks, workspace retention, and current capabilities. Update it when those operational behaviors change. Use concise Conventional Commit subjects and scope commits to requested files. Do not push or deploy without authorization for the current task.