Skip to main content
← Back to list
01Issue
FeatureClosedSwamp CLI
AssigneesNone

Relationships

#1469 Configurable write paths for object-creating commands (repo-relative swamp root)

Opened by jasonbarnett · 7/29/2026

Problem Statement

In a monorepo, swamp's out-of-the-box layout puts swamp-owned directories at the repo root: swamp repo init creates models/, workflows/, vaults/, and grants/ there, and extension trees are expected at extensions/<kind>/. A monorepo usually already has a convention for where a tool's source lives — ours nests everything under src/swamp/, so we want src/swamp/models/, src/swamp/workflows/, and src/swamp/extensions/<kind>/. Root-level models/, workflows/, and extensions/ collide with that convention and with the other tooling that owns the repo root.

The asymmetry is that the read path is configurable but the write path is not.

The repo marker accepts modelsDir, vaultsDir, driversDir, datastoresDir, reportsDir, and workflowsDir (plus the matching SWAMP_<KIND>_DIR env vars), but those only steer extension discovery — the extensions/<kind>/ load path. The commands that create repo objects ignore them entirely and write to hardcoded repo-relative directories:

Command Writes to Hardcoded in
swamp model create <repoDir>/models/ YamlDefinitionRepository
swamp vault create <repoDir>/vaults/ YamlVaultConfigRepository
swamp workflow create <repoDir>/workflows/ YamlWorkflowRepository

Each is a join(repoDir, "<name>") default, and swamp repo init scaffolds the same set at the root unconditionally. None of the three commands exposes a directory flag — workflow create takes only --repo-dir.

The practical consequence: authoring a workflow that belongs with our extension tree is a create-then-move. Once moved under extensions/workflows/, it loads as an extension workflow, which is read-only — swamp workflow edit and swamp workflow delete no longer apply to it, since they only see repo workflows. So the CLI's authoring loop is available for objects in the default location and unavailable for the same objects in the location our repo layout requires. Model definitions and vault configs have the same shape.

Proposed Solution

  1. A single repo-relative root in the marker — e.g. swampDir: src/swamp — that every default path hangs off, so one key yields src/swamp/models/, src/swamp/workflows/, src/swamp/vaults/, and src/swamp/extensions/<kind>/. Setting six-plus individual <kind>Dir keys per repo works, but it is a lot of ceremony for what is really one decision.

  2. Honor the configured directories on write, not just on read — for swamp model create, swamp vault create, swamp workflow create, and the swamp repo init scaffolding. The plumbing is nearly in place already: all three YAML repositories accept an optional baseDir constructor argument; the create*Deps(repoDir) factories simply never pass one.

  3. Let swamp repo init take the layout up front (flag or prompt) and persist it to .swamp.yaml, so a repo is laid out correctly from the first command instead of being reorganized afterward.

  4. If separate per-kind keys remain the model, distinguish read from write in the docs and naming — the current <kind>Dir keys read as though they govern both, which is what led us to try them first.

Alternatives Considered

  • Create-then-move (what we do today). Costs the CLI authoring loop: once a workflow lives in an extension tree it is read-only, so swamp workflow edit / delete stop working and the file has to be edited by hand. It also requires the extension source's only filter to include the kind, which is an easy thing to miss — a only: [models] source silently ignores workflow YAML placed beside it.

  • --repo-dir pointed at a subdirectory. swamp workflow create x --repo-dir src/swamp/extensions does write to src/swamp/extensions/workflows/, but the command requires an initialized repo at that path, so it means running swamp repo init inside the extension tree — a second marker, a second .swamp/ runtime directory, and agent files where they do not belong.

  • SWAMP_REPO_DIR=src/swamp. The closest workaround, and it does put objects under src/swamp/, but it relocates the entire repo root including .swamp/ runtime state, and it still cannot place the extension tree and the object directories independently.

  • Symlinking root directories into src/swamp/. Fragile, invisible to anyone reading the repo, and awkward on Windows.

Additional Context

Version: 20260729.212638.0-sha.45d9ed58

Target layout:

src/swamp/
  models/
  vaults/
  workflows/
  extensions/
    models/
    workflows/

Worth noting that the reading half of this already works well: extension sources in .swamp-sources.yaml accept an arbitrary path plus an only filter, so pointing swamp at src/swamp/extensions for discovery is a solved problem. The gap is entirely on the write and scaffold side — which is also why the inconsistency is surprising in practice: swamp can already load extensions from wherever we keep them, but cannot create objects there.

02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED

Closed

7/29/2026, 11:18:48 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

stack72 commented 7/29/2026, 11:18:48 PM

Hey @jasonbarnett — thanks for the detailed write-up. After looking at this, we think the existing --repo-dir flag (or SWAMP_REPO_DIR env var) already covers this use case.

The pattern would be:

  1. Run swamp repo init inside src/swamp/
  2. From the monorepo root, pass --repo-dir src/swamp (or set SWAMP_REPO_DIR=src/swamp)

This gives you the layout you're after — src/swamp/models/, src/swamp/workflows/, src/swamp/vaults/ — and the full authoring loop (create/edit/delete) works because swamp treats src/swamp/ as its repo root. Reads and writes are unified under the same directory.

This is the same pattern we use internally for running swamp from Claude worktrees against the main repo root, and it works well. The --repo-dir flag was built specifically for the "I'm standing somewhere else but swamp lives over there" scenario.

We're going to close this one out since the functionality exists today, but let us know if --repo-dir doesn't cover something in your setup — happy to dig in further.

jasonbarnett commented 7/30/2026, 2:22:08 PM

@stack72 Thanks for looking at this — you're right, and I checked before replying rather than taking your word or mine. I built a throwaway monorepo and ran exactly the pattern you described:

  • swamp repo init src/swamp, then from the monorepo root swamp workflow create test-flow --repo-dir src/swamp → landed at src/swamp/workflows/workflow-<uuid>.yaml. get, search, and delete all worked from the monorepo root too, and SWAMP_REPO_DIR=src/swamp behaved identically. Full authoring loop, exactly as you said.
  • Everything stayed self-contained under src/swamp/models/, vaults/, workflows/, grants/, .swamp/, plus its own .gitignore. The monorepo root .gitignore was left untouched, which is tidier than I expected.
  • I had something wrong in the issue: the extension tree relocates too. src/swamp/extensions/models/ was discovered with no .swamp-sources.yaml and no <kind>Dir overrides, because those defaults are repo-root-relative. That covers the src/swamp/extensions/ half of my request outright, and my write-up under-credited it.
  • For anyone who finds this later: from inside the swamp subtree no flag is needed at all — ancestor discovery finds the marker — and from elsewhere in the monorepo you get a clean, actionable error rather than silent misbehavior.

So the functionality claim holds and I have no argument with closing on those grounds.

Worth setting my context straight, since my write-up probably implied more than is true: I am evaluating swamp, not rolling it out. Part of evaluating it is trying to find the operational rough edges early and work out whether they have good answers, which is what prompted the issue. So please read the below as a question about direction rather than a request from an existing deployment.

The thing I am still turning over is that the configuration lives per developer — an alias, a shell profile, or an exported env var — rather than in the repo. If this did get adopted broadly here it would eventually mean on the order of a couple hundred engineers on mixed shells and operating systems, with varying levels of control over what can be enforced on endpoints. At that shape, "every engineer must export SWAMP_REPO_DIR or keep an alias" is the kind of per-machine setup step that tends to be hard to keep true over time: onboarding, machine rebuilds, CI images, and agents that shell out from the repo root would each need it satisfied independently, and a miss is corrected per person rather than once, centrally. That is the sort of thing I would rather understand now than discover later.

A key in the committed .swamp.yaml would have the property I am looking for: it travels with the clone, it is reviewable in a PR, and it is identical for every engineer and every CI job with no local setup. That is the whole of the ask — not new capability, just the option to move that decision from the environment into the repo. It also seems adjacent to something the marker already does, since it carries modelsDir / workflowsDir and friends for the read path today; the surprise was that those keys do not extend to writes.

If that is not a direction you want to take, that is a fine answer and useful input for my evaluation — --repo-dir plus a documented convention is workable. But if a marker-level key is something you would consider, it would resolve this one cleanly, and I am happy to help test it.

Sign in to post a ripple.