Merge branch 'feat/tool-config-mount-cleanup' into dev
This commit is contained in:
@@ -232,20 +232,6 @@ def upgrade() -> None:
|
|||||||
"writable": True,
|
"writable": True,
|
||||||
"owner": "user",
|
"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": {
|
"runtime": {
|
||||||
"command": ["/bin/bash"],
|
"command": ["/bin/bash"],
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -103,11 +103,8 @@ services:
|
|||||||
image: node:20-slim
|
image: node:20-slim
|
||||||
container_name: {{TOOL_NAME}}
|
container_name: {{TOOL_NAME}}
|
||||||
working_dir: /workspace
|
working_dir: /workspace
|
||||||
environment:
|
|
||||||
- HOME=/tmp
|
|
||||||
volumes:
|
volumes:
|
||||||
- {{REPO_PATH}}:/workspace
|
- {{REPO_PATH}}:/workspace
|
||||||
- opencode_home:/tmp
|
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
command: >
|
command: >
|
||||||
@@ -125,10 +122,7 @@ services:
|
|||||||
exec tail -f /dev/null"
|
exec tail -f /dev/null"
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: true
|
tty: true
|
||||||
restart: unless-stopped
|
restart: unless-stopped""",
|
||||||
|
|
||||||
volumes:
|
|
||||||
opencode_home:""",
|
|
||||||
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
"required_variables": ["REPO_PATH", "TOOL_NAME"],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
name: tool-config-mount-cleanup
|
||||||
|
status: completed
|
||||||
|
completed_at: 2026-06-13
|
||||||
|
started_at: 2026-06-12
|
||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user