11 KiB
CLI Config, Socket, And Storage Separation
Summary
Separate machine config, server target, and server storage so the CLI no longer conflates:
- config path:
~/.fabro/settings.toml - default socket target:
~/.fabro/fabro.sock - default storage dir:
~/.fabro/storage
Normal user-facing commands should always talk to a server target. A Unix socket target may auto-start the daemon. An HTTP target may not. Serverless/direct-storage command behavior should be removed from normal commands in this pass.
Scope Boundaries
In scope:
- add
FABRO_CONFIGsupport for machine settings loading - default the server target to
~/.fabro/fabro.sock - default server storage to
~/.fabro/storage - decouple socket-path resolution from storage-dir resolution
- keep daemon auto-start only for Unix socket targets
- remove normal-command fallback to direct storage-based targeting
- keep
fabro server *, hiddenfabro __runner, andfabro installas storage-owning commands - keep user-facing
--serveron server-targeted commands - remove user-facing
--storage-dirfrom server-targeted commands
Out of scope:
fabro execfabro system dffabro system prunefabro store dump- new remote maintenance endpoints for deferred commands
Problem Frame
The current CLI still mixes together two different ideas:
- a local daemon reached over a Unix socket
- serverless behavior where the CLI uses
storage_diras the command target
That has produced the wrong defaults and the wrong abstractions:
- the socket path is currently derived from
storage_dir - many commands still model targeting as "server or storage dir"
- normal commands can still fall back to a storage-driven local connection shape
- autostart is keyed off the local/storage connection path instead of the actual server target type
The intended model is simpler:
- normal commands always resolve a server target
- the default server target is a Unix socket in
~/.fabro - Unix socket targets may auto-start a daemon
- HTTP targets may not auto-start a daemon
- storage is server-owned runtime state, not the primary targeting mechanism for normal commands
Key Decisions
FABRO_CONFIGselects the active machine settings file.- For server lifecycle commands and daemon auto-start, precedence is: explicit
--configwhere supported, thenFABRO_CONFIG, then~/.fabro/settings.toml. - Normal user-facing commands do not gain a new
--configflag in this pass; they resolve settings fromFABRO_CONFIGor the default path.
- For server lifecycle commands and daemon auto-start, precedence is: explicit
FABRO_SERVERselects the effective server target for normal commands.- It accepts either an absolute Unix socket path or an
http(s)URL. - If unset, use
settings.server.target. - If that is unset, default to
~/.fabro/fabro.sock.
- It accepts either an absolute Unix socket path or an
- Server-targeted commands keep
--serveras the standard one-off override.FABRO_SERVERremains the env-var equivalent.
FABRO_STORAGE_DIRis no longer a normal command-targeting mechanism.- It remains an override for storage-owning commands only.
- Precedence for storage-owning commands: explicit
--storage-dirwhere still supported, thenFABRO_STORAGE_DIR, thensettings.storage_dir, then~/.fabro/storage.
settings.server.targetremains the durable place to configure the machine's server target.settings.storage_dirremains the durable place to configure where the local server stores data.fabro server startkeeps--configand--bind.- Its default bind is
~/.fabro/fabro.sock, not<storage_dir>/fabro.sock.
- Its default bind is
fabro server stopandfabro server statusremain storage-owning commands and continue to resolve the local server instance from storage-owned records.fabro settingsis a local config-inspection command, not a server-targeted command.- It keeps its current local settings-resolution behavior in this pass.
fabro execis unchanged in this pass.
Command Classification
Storage-owning commands
These commands continue to resolve and use local storage directly:
fabro server startfabro server stopfabro server status- hidden
fabro server __serve - hidden
fabro run __runner fabro install
Local config-inspection commands
These commands stay outside the server-targeting cleanup in this pass:
fabro settings
Server-targeted commands
These commands should resolve a ServerTarget only and should not use storage-dir fallback semantics:
fabro runfabro createfabro preflightfabro validatefabro graphfabro model listfabro model testfabro doctorfabro repo initfabro provider loginfabro secret listfabro secret rmfabro secret setfabro psfabro rmfabro inspectfabro run startfabro run attachfabro run logsfabro run resumefabro run rewindfabro run forkfabro run wait- hidden
fabro run diff fabro artifact listfabro artifact cpfabro sandbox cpfabro sandbox previewfabro sandbox sshfabro pr createfabro pr listfabro pr viewfabro pr mergefabro pr close
Deferred local-maintenance commands
These remain unchanged in this pass:
fabro system dffabro system prunefabro store dump
These deferred commands continue to use StorageDirArgs and the existing hybrid ServerRunLookup::connect(storage_dir) path in this pass, and should keep working against the new default storage dir without being reclassified as server-targeted commands yet.
Implementation Changes
1. Shared settings and path resolution
- Add a shared helper for the active settings path used by CLI and server code.
- This helper must honor
FABRO_CONFIG.
- This helper must honor
- Add a shared helper for the default socket path:
~/.fabro/fabro.sock. - Change the default storage dir helper to return
~/.fabro/storage. - Stop deriving the socket path from
storage_dir.
2. Target resolution model
- Refactor CLI target resolution so normal commands resolve a
ServerTarget, not a "local vs target" union. - Remove
ServerConnection::Localas a normal command-routing concept. - Split helpers into two categories:
- server-target resolution for normal commands
- storage-dir resolution for storage-owning commands
- Keep TLS handling attached to
HttpUrltargets exactly as today.
3. Connection and auto-start behavior
- Update the server client helpers so they accept or derive a
ServerTarget. - If the resolved target is
UnixSocket(path):- attempt to connect to that socket
- if unavailable, auto-start the daemon
- auto-start the daemon bound to that exact socket path
- If the resolved target is
HttpUrl(url):- attempt to connect once
- if unavailable, fail with a clean reachability error
- do not auto-start anything
- Auto-start must pass the active config path through to the spawned server with
--config. - The auto-start helper should take the resolved active config path, resolved Unix socket path, and resolved local storage dir as explicit inputs.
- It should not rediscover config via environment variables or reload settings internally during daemon launch.
- Auto-start may also pass the resolved storage dir for the local server process, but only as runtime/server lifecycle plumbing, not as the command target abstraction.
- Any active-server record lookup used by
server stop,server status,install, or daemon auto-start should temporarily fall back to the legacy implicit storage root~/.fabrowhen no explicit storage location is provided and no record exists under the new default~/.fabro/storage.- This is only to find already-running daemons started before the default-storage change.
4. CLI arg surface cleanup
- Keep user-facing
--serveron all server-targeted commands listed above. - Remove user-facing
--storage-dirfrom all server-targeted commands listed above. - Remove the
storage_dir_explicitconflict plumbing for those commands. - Remove the custom
--server/--storage-dirconflict detection inmain.rsonce no supported command still accepts both flags together. - Keep
--storage-dironly on storage-owning commands in this pass. - Keep
--configonly where already appropriate for server lifecycle. - Update help text and parser tests so normal commands still advertise
--serverbut no longer imply that storage-dir is a general targeting control.
5. Run/create local run-dir handling
run/createcurrently thread a synthesized local run dir through the result object to print asset paths after completion.- Preserve that behavior only when the effective target is the machine's local Unix socket and the effective local storage dir is known.
- For HTTP targets, do not synthesize a local run dir.
- This should be derived from "effective target is local socket" plus resolved storage dir, not from a
ServerConnection::Localenum variant.
6. Docs and user-visible messaging
- Rewrite docs and examples so:
- normal commands use config-driven target resolution by default
- temporary overrides use
FABRO_SERVER=... fabro ... - config-file overrides use
FABRO_CONFIG=... fabro ...
- Update language to avoid "local mode" as a user-facing concept.
- Use "Unix socket target" or "HTTP target".
- Use "serverless" only for the behavior being removed.
- Make
doctorandsettingsprint:- active config path
- effective server target
- effective storage dir
- any active env-var overrides
Test Plan
- Unit tests for path and precedence helpers:
- active config path honors
FABRO_CONFIG - default socket path is
~/.fabro/fabro.sock - default storage dir is
~/.fabro/storage FABRO_SERVERoverridessettings.server.targetFABRO_STORAGE_DIRoverridessettings.storage_dirfor storage-owning commands onlyFABRO_CONFIG=/custom/path/settings.tomlloads that file's contents and the resolvedserver.target/storage_dirfrom that file actually take effect
- active config path honors
- Unit tests for target resolution:
- normal commands default to a Unix socket target when nothing is configured
- normal commands no longer resolve a storage-dir fallback connection
- HTTP targets never route into autostart code
- Integration tests for daemon behavior:
fabro server startdefaults to binding~/.fabro/fabro.sock- auto-start for socket-targeted commands binds the requested socket, not
<storage_dir>/fabro.sock - auto-start passes the active config path through to the daemon
- HTTP-targeted commands fail cleanly when unreachable
server stop/server statusstill find an already-running daemon whose record lives under the legacy implicit storage root
- Parser/help tests:
- server-targeted commands still accept
--server - server-targeted commands no longer accept
--storage-dir - storage-owning commands still accept
--storage-dirwhere intended fabro settingskeeps its existing local settings override surface in this pass
- server-targeted commands still accept
- Workflow behavior tests:
run,create,model,doctor,ps, andsecretwork via the default socket target- local Unix socket runs still print local asset/run-dir info when appropriate
- HTTP-targeted runs do not print synthesized local run-dir paths
Assumptions
- This is a hard cut for CLI targeting semantics. No deprecation period for removed normal-command flags.
FABRO_SERVERis the single override for user-facing command targeting; no separateFABRO_SOCKETenv var is added.server.targetremains the canonical durable target field insettings.toml.- Deferred commands will be handled in a later pass rather than forced into this refactor.