# Read-only Workspace Runtime Secrets Implementation Plan > **Historical nomenclature:** this plan predates the native host CLI convergence. References to > `thothctl` and `tools/thothctl` describe the implementation snapshot from which this plan was > written; current operator commands and paths use native `tht` and `tools/tht`. > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Make workspace consumption strictly read-only while adding installation-scoped Git identity and persistent GUI-managed runtime secrets. **Architecture:** Git remains the source of truth and is fetched into an application-owned checkout; complete candidate commits are validated before atomic activation and the backend has no Git write path. Runtime connector credentials are discovered from trusted connector contracts, stored as authenticated ciphertext by a backend vault, and materialized only for the lifetime of diagnostics or runtime leases. The browser exposes repository/readiness status and write-only secret forms without workspace persistence. **Tech Stack:** Fastify, TypeScript, Node.js crypto/filesystem, React 18, TanStack Query, Vitest, Go `thothctl`, Docker Compose. --- ### Task 1: Freeze the Git repository boundary to read-only **Files:** - Modify: `backend/src/workspaces/types.ts` - Modify: `backend/src/workspaces/git-repository.ts` - Modify: `backend/src/workspaces/registry.ts` - Modify: `backend/test/workspaces-git-repository.test.ts` - Modify: `backend/test/workspace-registry.test.ts` - Modify: `backend/test/workspace-registry-deployment.test.ts` **Step 1: Write failing tests** Add tests proving that pull never configures a Git author, writes generated files, commits, or pushes; that a malformed candidate leaves the prior active snapshot intact; and that a missing catalog descriptor rejects the whole candidate instead of producing a bootstrap slot. **Step 2: Run the focused tests** Run: `cd backend && npx vitest run test/workspaces-git-repository.test.ts test/workspace-registry.test.ts test/workspace-registry-deployment.test.ts` Expected: FAIL on write/publish behavior and missing-descriptor semantics. **Step 3: Implement the read-only boundary** Remove `gitAuthorName`, `gitAuthorEmail`, mutation helpers, generated-document reconciliation, publish/conflict types, and bootstrap-slot activation. `pull()` must fetch, validate the complete commit in a candidate snapshot, and replace active state only after validation succeeds. **Step 4: Run focused tests** Run the command from Step 2. Expected: PASS. **Step 5: Commit** ```bash git add backend/src/workspaces backend/test/workspaces-git-repository.test.ts backend/test/workspace-registry.test.ts backend/test/workspace-registry-deployment.test.ts git commit -m "refactor: make workspace repository strictly read only" ``` ### Task 2: Remove publishing and bundle HTTP contracts **Files:** - Modify: `backend/src/routes/workspaces.ts` - Modify: `backend/test/routes-workspaces.test.ts` - Modify: `backend/test/workspaces-runtime-v3-boundaries.test.ts` - Modify: `backend/src/config.ts` - Modify: `backend/test/workspaces-config.test.ts` **Step 1: Write failing route tests** Assert `POST /workspaces/publish`, `GET /workspaces/:id/export`, and `POST /workspaces/import` return 404 and that the backend no longer registers multipart or ZIP handling. Assert configuration no longer accepts Git author or bundle-limit settings as workspace-registry fields. **Step 2: Run tests and observe failure** Run: `cd backend && npx vitest run test/routes-workspaces.test.ts test/workspaces-config.test.ts test/workspaces-runtime-v3-boundaries.test.ts` Expected: FAIL because mutation and bundle routes still exist. **Step 3: Remove the mutation surface** Delete publish/import/export schemas and helpers, remove `multipart`, `yauzl`, and `yazl` usage from the route, and simplify safe workspace errors to read/validate/sync errors. **Step 4: Run tests** Run the command from Step 2 plus `cd backend && npx tsc --noEmit -p .`. Expected: PASS. **Step 5: Commit** ```bash git add backend/src backend/test package.json package-lock.json git commit -m "refactor: remove workspace publishing and bundles" ``` ### Task 3: Expose a sanitized installation repository identity **Files:** - Modify: `backend/src/workspaces/git-repository.ts` - Modify: `backend/src/routes/workspaces.ts` - Modify: `backend/test/workspaces-git-repository.test.ts` - Modify: `backend/test/routes-workspaces.test.ts` - Modify: `tools/thothctl/internal/config/installation.go` - Modify: `tools/thothctl/internal/config/installation_test.go` - Modify: `deploy/psd/thothii-installation.yaml.example` - Modify: `docs/install/examples/thothii-installation.local.yaml` - Modify: `docs/install/examples/thothii-installation.server.yaml` **Step 1: Write failing parser and status tests** Cover HTTPS, SSH URL, and SCP-style remotes; reject embedded user-info for HTTPS; return only `host`, `repository`, `branch`, and `transport`; never return a token, key path, or raw credential-bearing URL. Add installation-descriptor tests for a required `workspaceRepository` block and exactly one read-only transport. **Step 2: Run focused tests** Run: `cd backend && npx vitest run test/workspaces-git-repository.test.ts test/routes-workspaces.test.ts && cd ../tools/thothctl && go test ./internal/config` Expected: FAIL because repository identity and typed installation configuration do not exist. **Step 3: Implement safe normalization and installation validation** Add the normalized identity to registry status. Extend `thothii-installation.yaml` with remote, branch, and SSH/HTTPS access metadata, validate it against the selected Compose override and environment without reading or returning secret values, and retain the existing environment rendering boundary. **Step 4: Run focused tests** Run the command from Step 2. Expected: PASS. **Step 5: Commit** ```bash git add backend tools/thothctl deploy docs/install/examples git commit -m "feat: declare workspace repository in installation config" ``` ### Task 4: Add the persistent encrypted workspace secret store **Files:** - Create: `backend/src/workspaces/secret-store.ts` - Create: `backend/test/workspace-secret-store.test.ts` - Modify: `backend/src/config.ts` - Modify: `backend/src/app.ts` - Modify: `compose.yaml` - Modify: `deploy/compose.local.yaml` - Modify: `deploy/compose.server.yaml` **Step 1: Write failing vault tests** Test first-start initialization, atomic blind replacement, deletion, enumeration by configured ID only, AES-256-GCM ciphertext with installation/workspace/field associated data, corruption failure, restrictive files/directories, size limits, and absence of plaintext in persistent bytes. **Step 2: Run the vault test** Run: `cd backend && npx vitest run test/workspace-secret-store.test.ts` Expected: FAIL because `WorkspaceSecretStore` does not exist. **Step 3: Implement the vault** Create an injectable `WorkspaceSecretStore` backed by an application-managed data root. Persist a versioned encrypted document atomically, generate or load the installation vault key in the private control area, expose only `has`, `put`, `delete`, and scoped materialization operations, and never add a plaintext read API. **Step 4: Run tests and typecheck** Run: `cd backend && npx vitest run test/workspace-secret-store.test.ts && npx tsc --noEmit -p .` Expected: PASS. **Step 5: Commit** ```bash git add backend compose.yaml deploy git commit -m "feat: persist encrypted workspace runtime secrets" ``` ### Task 5: Derive connector requirements and integrate temporary materialization **Files:** - Create: `backend/src/workspaces/secret-requirements.ts` - Create: `backend/test/workspace-secret-requirements.test.ts` - Modify: `backend/src/workspaces/bindings.ts` - Modify: `backend/src/workspaces/runtime-config-lease.ts` - Modify: `backend/src/tht/tht-runner.ts` - Modify: `backend/src/app.ts` - Modify: `backend/test/workspace-runtime-config-lease.test.ts` - Modify: `backend/test/workspace-runtime-handoff.test.ts` - Modify: `backend/test/workspaces-bindings.test.ts` **Step 1: Write failing requirement and lifecycle tests** Cover PostgreSQL password, REST bearer API key, unauthenticated REST, SSH private key/password, signed HTTP Evidence, and static S3 credentials. Assert temporary files are restrictive, live for exactly one diagnostic/runtime lease, disappear on release and error, and are never persisted in the encrypted vault document. **Step 2: Run focused tests** Run: `cd backend && npx vitest run test/workspace-secret-requirements.test.ts test/workspaces-bindings.test.ts test/workspace-runtime-config-lease.test.ts test/workspace-runtime-handoff.test.ts` Expected: FAIL because requirements still come from installation secret-file paths. **Step 3: Implement dynamic requirement resolution** Use the selected DWH transport and Evidence authentication contract to map trusted installation-contract suffixes to stable GUI requirement IDs. Overlay materialized temporary file paths only while resolving existing file-oriented connectors, and attach cleanup to every runtime lease. **Step 4: Run tests and typecheck** Run the command from Step 2 plus `cd backend && npx tsc --noEmit -p .`. Expected: PASS. **Step 5: Commit** ```bash git add backend/src backend/test git commit -m "feat: resolve workspace secrets from connector requirements" ``` ### Task 6: Add write-only workspace secret and readiness APIs **Files:** - Modify: `backend/src/routes/workspaces.ts` - Modify: `backend/src/app.ts` - Modify: `backend/src/workspaces/types.ts` - Modify: `backend/test/routes-workspaces.test.ts` **Step 1: Write failing API tests** Test `GET /workspaces/:id/runtime-configuration`, blind `PUT /workspaces/:id/secrets`, and `DELETE /workspaces/:id/secrets/:requirementId`. Assert strict bodies, limits, unknown-ID rejection, status-only responses, diagnostic invalidation, and `configuration_required`/`ready` state transitions. **Step 2: Run tests** Run: `cd backend && npx vitest run test/routes-workspaces.test.ts` Expected: FAIL because the routes do not exist. **Step 3: Implement the routes and readiness projection** Inject the secret store into workspace routes and runtime support. Compute per-workspace readiness from active descriptor, current requirement set, configured IDs, and diagnostic generation. Materialize values only inside the diagnostic request and always clean up. **Step 4: Run backend gates** Run: `cd backend && npx vitest run && npx tsc --noEmit -p . && npm run build`. Expected: PASS. **Step 5: Commit** ```bash git add backend git commit -m "feat: manage runtime workspace secrets through the API" ``` ### Task 7: Replace workspace management with the two-level read-only UI **Files:** - Modify: `frontend/src/api/workspaces.ts` - Modify: `frontend/src/api/workspaces.test.ts` - Modify: `frontend/src/shell/WorkspaceManager.tsx` - Modify: `frontend/src/shell/WorkspaceManager.test.tsx` - Delete: `frontend/src/shell/WorkspacePublishDialog.tsx` - Delete: corresponding publish-dialog tests - Modify/Delete: `frontend/src/shell/WorkspaceEditor.tsx` and bootstrap-only tests as references permit - Modify: `frontend/src/workspaces/drafts.ts` - Modify: `frontend/src/workspaces/drafts.test.ts` **Step 1: Write failing UI/API tests** Assert the dialog uses at least 60% viewport width and height, shows general repository concepts and exact button consequences at level 1, gates workspace-specific controls on selection, renders requirement explanations and write-only fields at level 2, and has no create/edit/publish/import/export/bundle controls. **Step 2: Run focused tests** Run: `cd frontend && npx vitest run src/api/workspaces.test.ts src/shell/WorkspaceManager.test.tsx src/workspaces/drafts.test.ts` Expected: FAIL on the old draft/publish interface. **Step 3: Implement the read-only interface** Replace bootstrap editor state with repository status, selection, validation/readiness details, dynamic secret fields, blind save/forget actions, and connection test. Remove workspace draft persistence and clear secret field component state after submit/close. **Step 4: Run focused tests and typecheck** Run the command from Step 2 plus `cd frontend && npx tsc -b`. Expected: PASS. **Step 5: Commit** ```bash git add frontend git commit -m "feat: add read-only workspace and secret management UI" ``` ### Task 8: Remove browser-persisted workspace preferences **Files:** - Modify: `frontend/src/workspaces/preferences.ts` - Modify: `frontend/src/workspaces/preferences.test.ts` - Modify: `frontend/src/api/sessions.ts` - Modify: `frontend/src/api/sessions.test.ts` - Modify: `frontend/src/shell/SteerInput.tsx` - Modify: `frontend/src/shell/SteerInput.test.tsx` **Step 1: Write failing persistence-boundary tests** Assert workspace/model/thinking choices are kept only in current application memory or saved through the existing backend settings API, and that no workspace code calls `localStorage`. **Step 2: Run focused tests** Run: `cd frontend && npx vitest run src/workspaces/preferences.test.ts src/api/sessions.test.ts src/shell/SteerInput.test.tsx` Expected: FAIL because preferences still use browser storage. **Step 3: Implement ephemeral preferences** Replace the storage adapter with an in-memory external store seeded from backend settings. Preserve concurrent workspace-policy gates and session request determinism without persisting selections in the browser. **Step 4: Run frontend gates** Run: `cd frontend && npx vitest run && npx tsc -b && npm run build`. Expected: PASS. **Step 5: Commit** ```bash git add frontend git commit -m "refactor: stop persisting workspace state in the browser" ``` ### Task 9: Update deployment contracts and documentation **Files:** - Modify: `compose.yaml` - Modify: `deploy/compose.git-ssh.yaml` - Modify: `deploy/compose.git-https.yaml` - Modify: `deploy/workspace-registry.env.example` - Modify: `deploy/psd/operator.env.example` - Modify: `docs/install/local-workspace-registry.md` - Modify: `docs/install/server-workspace-registry.md` - Modify: `docs/guida-utente.md` - Modify: `scripts/verify-workspace-install-docs.sh` - Modify: `scripts/workspace-registry-smoke.sh` **Step 1: Update executable contract tests first** Require read-only Git wording and configuration, repository identity visibility, vault persistence, and absence of author/push/bundle/browser-secret instructions. **Step 2: Run contract tests and observe failure** Run: `bash scripts/verify-workspace-install-docs.sh` Expected: FAIL against the old manuals and examples. **Step 3: Update deployment and manuals** Remove Git author settings and write-oriented documentation. Document installation Git bootstrap, GUI runtime-secret completion, platform-neutral application storage, rotation/forget flows, and candidate validation semantics. **Step 4: Run contract and Go gates** Run: `bash scripts/verify-workspace-install-docs.sh && cd tools/thothctl && go test ./...` Expected: PASS. **Step 5: Commit** ```bash git add compose.yaml deploy docs scripts tools/thothctl git commit -m "docs: describe read-only workspace runtime configuration" ``` ### Task 10: Full verification and deployed-container refresh **Files:** - Modify only files needed to fix failures found by verification. **Step 1: Run static and unit gates** ```bash cd backend && npx vitest run && npx tsc --noEmit -p . && npm run build cd ../frontend && npx vitest run && npx tsc -b && npm run build cd ../harness && .venv/bin/pytest -q cd ../tools/thothctl && go test ./... ``` Expected: all gates PASS. **Step 2: Run deployment contract gates** Run: `bash scripts/verify-workspace-install-docs.sh` and the focused workspace registry smoke appropriate to the configured installation. Expected: PASS without Git writes or secret disclosure. **Step 3: Inspect the final diff and secret scan** Run: `git diff --check`, inspect `git status --short`, and search active code/config for removed publish, bundle, Git author, and workspace-localStorage contracts. Expected: no whitespace errors, no accidental secrets, and only intended changes. **Step 4: Rebuild and restart affected services** Use the installation-aware `thothctl` lifecycle for the configured installation to rebuild/restart `core` and `frontend`, then verify health and repository status. Do not restart if no valid local installation descriptor is available; report that external gate explicitly. **Step 5: Commit verification fixes** ```bash git add git commit -m "test: verify read-only workspace secret flow" ```