Skip to content

Phase 8: Ports, Git, and actions

Implemented

  • Added a declared/reserved/bound port domain with accepted-manifest and Compose provenance, SQLite-backed stopped-project reservations, attributed runtime bindings, deduplicated lsof TCP/UDP listeners, stable conflict IDs, wildcard-host reasoning, partial-source warnings, and preferred-range suggestions with exclusions.
  • Added fresh read-only Git observation using porcelain v2, including branch or detached state, staged/modified/untracked/conflicted counts, ahead/behind, stash count, last commit, remotes, worktrees, and merge/rebase state.
  • Added typed and risk-classified manifest actions plus built-in terminal, VS Code, Codex, Claude Code, Git pull, and accepted endpoint actions.
  • Added durable action.run operations with destructive confirmation, cancellation and timeouts, symlink-aware root containment, explicit outside-root permission, a narrow environment allowlist, bounded optional output capture, explicit shell opt-in, and privilege-escalation rejection.
  • Added macOS terminal, editor, agent, and HTTP/HTTPS browser launch adapters. Terminal and agent tests assert the exact resolved working directory.
  • Added redaction-safe action audit persistence and daemon-restart recovery.
  • Added generated OpenAPI Go and TypeScript clients, private IPC clients, CLI commands, a live port registry, and project Git/quick-action UI slices.
  • Added one deterministic port-conflict visual reference and extended real browser onboarding coverage through Git, actions, and port evidence.
  • Added durable preferred port ranges and exclusions used by browser suggestions, plus durable terminal/editor preferences that filter built-in quick actions without changing explicitly accepted manifest actions.

Files and modules added

  • internal/ports/{domain,application,adapters}
  • internal/sourcecontrol/{domain,application,adapters}
  • internal/actions/{domain,application,adapters}
  • internal/platform/sqlite/ports.go
  • internal/platform/sqlite/action_audit.go
  • internal/transport/cli/developer_commands.go
  • internal/transport/httpapi/developer_handler.go
  • migrations/00006_ports_actions.sql
  • web/src/domains/ports
  • web/src/domains/projects/components/ProjectDeveloperTools.vue
  • docs/architecture/developer-workflows.md

Architecture decisions

No new ADR was required. The implementation realizes the existing modular monolith, manifest precedence, SQLite, local transport security, log/audit redaction, and platform-order decisions. Port, source-control, and action policy remain separate application boundaries. macOS was the first native launcher; Phase 18 subsequently added the Linux and Windows adapters required by ADR-0015.

Action commands are never built by UI or transport code. The generated API submits a durable operation, and the operation executor invokes the trusted action service. This retains one cancellation, serialization, recovery, and event model rather than adding an action-specific job system.

Tests added

  • Port declaration/reservation/binding reconciliation, stopped-vs-running conflict visibility, same-project service conflicts, logical-claim de-duplication, wildcard hosts, unknown listeners, listener-row de-duplication, and suggestion exclusions.
  • Real temporary Git repository updates after a file change plus porcelain branch/change/commit/worktree parsing.
  • Manifest action invariants, destructive confirmation, parent and symlink escape rejection, explicit escape permission, exact terminal working directory, command cancellation, environment allowlisting, and sudo/doas rejection.
  • SQLite reservation cleanup, audit outcome persistence, and schema migration 6.
  • HTTP empty-array contracts and confirmed/unconfirmed action operation paths.
  • Vue conflict, Git, action, loading/error, and free-port suggestion states.
  • Playwright real-daemon and deterministic visual coverage.

Verification evidence

go test ./internal/actions/... ./internal/manifest/...
PASS
go test ./internal/ports/...
PASS
make lint
PASS: gofmt, go vet, golangci-lint, architecture check, frontend ESLint
pnpm --dir web typecheck
pnpm --dir web test
PASS
pnpm --dir web test:e2e
PASS: 2 real-daemon browser flows
pnpm --dir web test:visual
PASS: system and deterministic port-conflict baselines
make build
PASS: production Vue bundle and packaged Go binary
make quality
PASS: generated-code drift, lint, typechecking, unit and race tests, fresh
database migration, vulnerability scan, isolated browser E2E, visual baselines,
and production build

Packaged acceptance used a fresh temporary schema-6 database and private Unix socket. The CLI trusted the action fixture, returned live Git branch/change and worktree state, listed the built-in and accepted actions, suggested port 15000/tcp after reading real host listeners, queued verify, and observed its durable operation reach succeeded. The audit row stored ipc, read_only, command, and the exact fixture root, with no output or environment values.

Acceptance criteria status

  • A stopped project’s persistent reservation conflicts with another project’s live binding before startup and is rendered with both sources.
  • Port evidence identifies accepted manifest, Compose-derived, runtime, and live OS-listener sources without collapsing their fact kinds.
  • Git state is read fresh and updates after file or repository changes.
  • Manifest approval and execution-time symlink resolution both prevent implicit escape from the trusted project root; execution requires an explicit permission to cross it.
  • The macOS terminal adapter is tested to launch at the exact resolved project working directory.

Known limitations and deferred work

  • Automatic repository rewriting for port remediation is intentionally out of scope. The registry explains conflicts and suggests a free port only.
  • Git commit, merge, rebase, and stash mutation UI is intentionally deferred.
  • Action output is bounded for process safety but is not yet a first-class log stream; persistent process and Compose logs continue to use the Phase 7 observability pipeline.

2026-07-17 terminal and endpoint evidence

  • Dashboard and project-header Terminal controls use the durable terminal preference: integrated opens Switchyard’s terminal tab, while an external preference queues the trusted terminal.open action. The terminal tab remains directly accessible in either mode.
  • The explicit external-terminal control is disabled when no trusted terminal.open action exists. On macOS, the launcher uses the selected Terminal.app or iTerm2 AppleScript API to open and focus a shell at the exact trusted working directory. Other platforms reject the macOS-only iTerm2 provider instead of silently substituting another terminal.
  • Every trusted browser.open action is rendered as a named project endpoint; browser and terminal actions are excluded from generic quick actions.
  • Project action failures preserve the server problem detail and code instead of replacing them with a generic queueing message.

2026-07-21 external-terminal preference evidence

  • Extended the existing durable terminal preference and generated API enum with an explicit iterm choice while preserving integrated and system values for existing settings.
  • Carried the selected provider through the trusted action definition and narrow launcher interface; no UI or transport code constructs a command.
  • Added settings validation, generated-contract, provider-routing, exact working-directory, unknown-provider, UI save, and preferred-button tests.
  • make lint, make typecheck, make test, make test-race, make platform-check, make test-e2e, make test-visual, make repository-check, and make build passed. Generated outputs were byte-identical across consecutive generation runs.
Use this pageLast verified Jul 21, 2026
Copy-ready MarkdownOpen sourceReport a docs issue