Skip to content

Fin Extension System Review (2026-02-25)

This document is a thorough performer review of the contract-v1 fin adapter implemented in recent commits, focused on:

  • compliance with the v1 spec/handoff requirements
  • what external users can do without modifying Shoal source
  • quality, risks, and concrete hardening steps

Reviewed commits:

  • c07731c feat: add fin contract v1 runtime and cli
  • a806dd1 docs: map extension capabilities and next milestones

Follow-up implementation status (2026-02-27):

  • Added shoal fin install and shoal fin configure
  • Added shoal fin ls [--path <dir-or-fin.toml>]
  • Added SHOAL_LOG_LEVEL propagation in fin runtime env handshake
  • Added cross-repo contract guard test using a scaffold generated by fins-template

Spec references:

  • ../fins-template/docs/fin-contract-v1.md
  • ../fins-template/docs/shoal-cli-fin-integration-handoff.md

Executive assessment

The Stage 1 adapter is implemented correctly and is usable for external, path-based fins. Users can author and run fins from outside Shoal and invoke them through shoal fin inspect|validate|run without editing Shoal code.

The biggest remaining limitations are lifecycle completeness (install, configure) and discovery ergonomics (fin ls / install sources), not core runtime correctness.

Spec compliance checklist

Requirement Status Evidence
Add shoal fin command group PASS src/shoal/cli/__init__.py registers fin typer
Implement inspect command PASS src/shoal/cli/fin.py fin_inspect()
Implement validate command with --strict PASS src/shoal/cli/fin.py fin_validate(); strict forwarded in src/shoal/services/fin_runtime.py
Implement run command with passthrough args after -- PASS src/shoal/cli/fin.py fin_run() and args passthrough
Parse fin.toml and validate schema PASS src/shoal/services/fin_runtime.py + src/shoal/models/fin.py
Enforce contract version v1 (fin_contract_version == 1) PASS src/shoal/services/fin_runtime.py explicit version gate
Resolve entrypoints from fin root and ensure executable PASS resolve_entrypoint() checks existence/file/executable
Prevent entrypoint escaping fin root PASS resolve() + relative_to(fin_root) guard
Execute fin wrappers as subprocesses PASS subprocess.run() in execute_entrypoint()
Invocation cwd is fin root PASS subprocess.run(..., cwd=fin_root, ...)
Set SHOAL_FIN_ROOT PASS _build_env() sets required variable
Set/unset SHOAL_FIN_CONFIG based on user input PASS _build_env() sets when present; removes when absent
Support SHOAL_OUTPUT_FORMAT text/json handshake PASS _build_env() sets value from CLI option
Preserve wrapper non-zero exit code at CLI boundary PASS typer.Exit(result.exit_code) in validate/run
Show stdout/stderr from wrapper PASS CLI echoes captured stdout/stderr
Include tests for arg passthrough and exit propagation PASS tests/test_cli_fin.py, tests/test_services_fin_runtime.py
Propagate SHOAL_LOG_LEVEL (recommended env var) PASS _build_env() derives level via getEffectiveLevel() (numeric), parent env override preserved
Stage 1 lifecycle completeness (install, configure) SHIPPED v0.22.0 shoal fin install, shoal fin configure
Discovery (fin ls, local registration) SHIPPED v0.22.0 fin ls defaults to installed; fin install --no-register opt-out

What users can do today without editing Shoal

Users can implement a fin externally (outside Shoal source), then:

  • inspect manifest + resolved entrypoints: shoal fin inspect <path>
  • run fin self-checks with strict mode: shoal fin validate <path> --strict
  • run fin capability with optional config and passthrough args: shoal fin run <path> --config <file> -- --arg1 --arg2

This is enough to support a practical external author workflow for path-based execution with a stable contract handshake.

Gaps affecting extension UX and platform completeness

  1. Lifecycle surface is partial
  2. ~~Missing first-class shoal fin install and shoal fin configure~~. — shipped in v0.22.0
  3. Discovery and distribution are absent
  4. ~~Missing shoal fin ls and local/remote source installation UX.~~ fin ls and local registration shipped in v0.22.0; remote/registry sources remain open.
  5. Completion ergonomics lag behind command surface
  6. Fish completions template does not yet advertise fin subcommands.
  7. Validation hardening can go deeper
  8. Current tests are good but do not yet cover malformed TOML and broader invalid-manifest permutations as explicitly called out in milestones.

Risk and quality notes

  • Good security boundary for Stage 1: entrypoint path escape is blocked.
  • Error quality is generally actionable and user-facing.
  • Runtime currently buffers all output and has no timeout controls; hung fins can block invocation indefinitely.
  • Manifest semantic constraints (like stricter identifier/version validation) are intentionally light for now.

Prioritized hardening plan (atomic)

P0: Close Stage 1 lifecycle parity

  1. ~~Add shoal fin install <fin-path> [--config <path>]~~ — shipped in v0.22.0
  2. ~~Add shoal fin configure <fin-path> [--config <path>]~~ — shipped
  3. Ensure the same env/exit behavior contract as run and validate
  4. Add shoal fin configure <fin-path> [--config <path>]
  5. Ensure the same env/exit behavior contract as run and validate

Acceptance:

  • install/configure wrappers execute with cwd=fin_root
  • exit-code propagation verified by tests
  • help text + README command table updated

P1: Discovery and local source ergonomics

  1. ~~Add shoal fin ls (start with local install roots)~~ — shipped in v0.22.0; fin ls defaults to registered fins
  2. ~~Add local source registration/install metadata (no marketplace yet)~~ — fin install now registers to ~/.config/shoal/fins/; --no-register opt-out available
  3. Keep explicit docs on what is and is not supported
  4. Add local source registration/install metadata (no marketplace yet)
  5. Keep explicit docs on what is and is not supported

Acceptance:

  • users can enumerate installed fins without path memorization
  • docs describe source model and trust implications

P2: Validation and runtime hardening

  1. Expand tests for malformed TOML and missing keys
  2. Add optional subprocess timeout support (--timeout or config default)
  3. Decide and document SHOAL_LOG_LEVEL propagation behavior

Acceptance:

  • malformed-manifest cases have deterministic errors and tests
  • hung entrypoint behavior is bounded and documented

P3: Author ergonomics polish

  1. Update fish completions template for fin command group/subcommands
  2. Improve diagnostics for common author mistakes (missing executable bit, contract mismatch, root path confusion)

Acceptance:

  • shoal setup fish installs completions that include fin
  • common failure modes have concise remediation hints

Recommendation on the core question

The current implementation does satisfy the immediate requirement of enabling external extension authors to use Shoal as an adapter without modifying Shoal source code for path-based workflows.

To satisfy the broader extension-system promise end-to-end, prioritize install/configure and discovery next; these are now the main blockers, not the contract runtime foundation.