From 8bde9a213c79408751379bd975007379f8305ed5 Mon Sep 17 00:00:00 2001 From: Developer Date: Sat, 13 Jun 2026 11:35:55 +0000 Subject: [PATCH] feat: remove config/state mounts from built-in tool configs - Remove pi_state and pi_config mounts from the pi-agent manifest. - Add Alembic data migration to strip those mounts from existing DB rows. - Remove opencode_home:/tmp volume and HOME=/tmp override from the opencode built-in compose template; config/state now belongs in config profiles. - Workspace and SSH key mounts remain unchanged. Quality gates: python3 -m py_compile, pytest (311 passed, 34 skipped), npm run typecheck, npm run lint --- ...026_05_28_add_tool_definition_manifests.py | 14 --- ...remove_pi_config_and_state_mounts_from_.py | 112 ++++++++++++++++++ apps/api/src/seeds/builtin_tool_types.py | 8 +- .../tool-config-mount-cleanup/.openspec.yaml | 4 + .../tool-config-mount-cleanup/proposal.md | 33 ++++++ .../tool-config-mount-cleanup/tasks.md | 8 ++ 6 files changed, 158 insertions(+), 21 deletions(-) create mode 100644 apps/api/alembic/versions/8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py create mode 100644 openspec/changes/tool-config-mount-cleanup/.openspec.yaml create mode 100644 openspec/changes/tool-config-mount-cleanup/proposal.md create mode 100644 openspec/changes/tool-config-mount-cleanup/tasks.md diff --git a/apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py b/apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py index 3bcae63..9f2d125 100644 --- a/apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py +++ b/apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py @@ -232,20 +232,6 @@ def upgrade() -> None: "writable": True, "owner": "user", }, - { - "name": "pi_state", - "target": "/tmp/.pi/agents", - "source_type": "instance", - "writable": True, - }, - { - "name": "pi_config", - "target": "/home/user/.pi", - "source_type": "git_mount", - "git_mount_ref": "dotfiles", - "writable": True, - "owner": "user", - }, ], "runtime": { "command": ["/bin/bash"], diff --git a/apps/api/alembic/versions/8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py b/apps/api/alembic/versions/8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py new file mode 100644 index 0000000..efc9e6d --- /dev/null +++ b/apps/api/alembic/versions/8c6d1dbd4798_remove_pi_config_and_state_mounts_from_.py @@ -0,0 +1,112 @@ +"""remove pi config and state mounts from pi-agent manifest + +Revision ID: 8c6d1dbd4798 +Revises: 2026_06_13_make_clone_mode_nullable +Create Date: 2026-06-13 11:21:25.983178 +""" + +import json + +from alembic import op +import sqlalchemy as sa + + + +# revision identifiers, used by Alembic. +revision = '8c6d1dbd4798' +down_revision = '2026_06_13_make_clone_mode_nullable' +branch_labels = None +depends_on = None + + +def _load_manifest(manifest_json): + return manifest_json if isinstance(manifest_json, dict) else json.loads(manifest_json) + + +def upgrade() -> None: + """Remove pi_state and pi_config mounts from the pi-agent manifest.""" + conn = op.get_bind() + + result = conn.execute( + sa.text( + "SELECT id, manifest FROM tool_definition_manifests WHERE name = 'pi-agent'" + ) + ) + row = result.fetchone() + if not row: + return + + manifest_id, manifest_json = row + manifest = _load_manifest(manifest_json) + + mounts = manifest.get("mounts", []) + original_count = len(mounts) + + filtered_mounts = [ + m for m in mounts if m.get("name") not in ("pi_state", "pi_config") + ] + + if len(filtered_mounts) < original_count: + manifest["mounts"] = filtered_mounts + conn.execute( + sa.text( + "UPDATE tool_definition_manifests SET manifest = :manifest WHERE id = :id" + ), + { + "manifest": json.dumps(manifest), + "id": manifest_id, + }, + ) + + +def downgrade() -> None: + """Restore pi_state and pi_config mounts to the pi-agent manifest.""" + conn = op.get_bind() + + result = conn.execute( + sa.text( + "SELECT id, manifest FROM tool_definition_manifests WHERE name = 'pi-agent'" + ) + ) + row = result.fetchone() + if not row: + return + + manifest_id, manifest_json = row + manifest = _load_manifest(manifest_json) + + mounts = manifest.get("mounts", []) + existing_names = {m.get("name") for m in mounts} + + if "pi_state" not in existing_names: + mounts.append( + { + "name": "pi_state", + "target": "/tmp/.pi/agents", + "source_type": "instance", + "writable": True, + } + ) + + if "pi_config" not in existing_names: + mounts.append( + { + "name": "pi_config", + "target": "/home/user/.pi", + "source_type": "git_mount", + "git_mount_ref": "dotfiles", + "writable": True, + "owner": "user", + } + ) + + manifest["mounts"] = mounts + conn.execute( + sa.text( + "UPDATE tool_definition_manifests SET manifest = :manifest WHERE id = :id" + ), + { + "manifest": json.dumps(manifest), + "id": manifest_id, + }, + ) diff --git a/apps/api/src/seeds/builtin_tool_types.py b/apps/api/src/seeds/builtin_tool_types.py index 1dacd52..c1f0184 100644 --- a/apps/api/src/seeds/builtin_tool_types.py +++ b/apps/api/src/seeds/builtin_tool_types.py @@ -103,11 +103,8 @@ services: image: node:20-slim container_name: {{TOOL_NAME}} working_dir: /workspace - environment: - - HOME=/tmp volumes: - {{REPO_PATH}}:/workspace - - opencode_home:/tmp ports: - "3000:3000" command: > @@ -125,10 +122,7 @@ services: exec tail -f /dev/null" stdin_open: true tty: true - restart: unless-stopped - -volumes: - opencode_home:""", + restart: unless-stopped""", "required_variables": ["REPO_PATH", "TOOL_NAME"], }, ] diff --git a/openspec/changes/tool-config-mount-cleanup/.openspec.yaml b/openspec/changes/tool-config-mount-cleanup/.openspec.yaml new file mode 100644 index 0000000..102a91f --- /dev/null +++ b/openspec/changes/tool-config-mount-cleanup/.openspec.yaml @@ -0,0 +1,4 @@ +name: tool-config-mount-cleanup +status: completed +completed_at: 2026-06-13 +started_at: 2026-06-12 diff --git a/openspec/changes/tool-config-mount-cleanup/proposal.md b/openspec/changes/tool-config-mount-cleanup/proposal.md new file mode 100644 index 0000000..337811a --- /dev/null +++ b/openspec/changes/tool-config-mount-cleanup/proposal.md @@ -0,0 +1,33 @@ +# Tool config mount cleanup + +## Problem + +The built-in tool definitions currently declare configuration and state mounts that belong in user-controlled config profiles: + +- The `pi-agent` manifest mounts `pi_state` (`/tmp/.pi/agents`) and `pi_config` (`/home/user/.pi`) via a `git_mount` reference. +- The `opencode` built-in compose template mounts a named volume `opencode_home:/tmp` and sets `HOME=/tmp`. + +These require manual configuration or implicit state persistence, which conflicts with the design that tool configs should only set up the actual tool, while config profiles handle user-specific configuration and state. + +## Decision + +Remove all configuration/state mounts from built-in tool definitions. Tool configs will declare only: + +- Runtime environment (packages, user, command, ports). +- The workspace/repository mount. +- SSH key mounts supplied by the platform. + +User-specific configuration and state will be handled exclusively by config profiles. + +## Scope + +- Remove `pi_state` and `pi_config` mounts from the `pi-agent` manifest. +- Update the original migration that inserts the `pi-agent` manifest. +- Add a data migration to remove those mounts from existing `tool_definition_manifests` rows. +- Remove the `opencode_home:/tmp` volume and `HOME=/tmp` override from the `opencode` built-in compose template. + +## Non-goals + +- No changes to config profile behavior. +- No changes to workspace or SSH key mounts. +- No changes to tool image Dockerfiles beyond what is required by mount removal. diff --git a/openspec/changes/tool-config-mount-cleanup/tasks.md b/openspec/changes/tool-config-mount-cleanup/tasks.md new file mode 100644 index 0000000..ddb2f33 --- /dev/null +++ b/openspec/changes/tool-config-mount-cleanup/tasks.md @@ -0,0 +1,8 @@ +# Tasks + +- [x] Identify all built-in tool configs with configuration or state mounts. +- [x] Remove `pi_state` and `pi_config` mounts from the `pi-agent` manifest in `apps/api/alembic/versions/2026_05_28_add_tool_definition_manifests.py`. +- [x] Create an Alembic data migration to remove those mounts from existing `tool_definition_manifests` rows. +- [x] Remove the `opencode_home:/tmp` volume and `HOME=/tmp` environment variable from the `opencode` compose template in `apps/api/src/seeds/builtin_tool_types.py`. +- [x] Run backend quality gates (`py_compile`, `pytest`). +- [x] Commit, merge to `dev`, push.