16 KiB
Read-only Workspace Runtime Secrets Implementation Plan
Historical nomenclature: this plan predates the native host CLI convergence. References to
thothctlandtools/thothctldescribe the implementation snapshot from which this plan was written; current operator commands and paths use nativethtandtools/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
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
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
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
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
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
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.tsxand 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
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
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
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
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
git add <only-files-changed-for-verification>
git commit -m "test: verify read-only workspace secret flow"