Skip to content

paddock service install silently records PADDOCK_DATA_DIR in the unit while its help text promises the service and your terminal share one instance #818

Description

@edspencer

paddock service install --help states an unconditional promise that the code only keeps conditionally. If PADDOCK_DATA_DIR is set in the shell you run install from, that path is written into the generated unit — and the help text says it isn't.

The behaviour looks deliberate and defensible. The help text and the changelog are what's wrong, and they are wrong in the direction that leaves a user with two instances they believe are one.

What the help text promises

SERVICE_USAGE, packages/server/src/cli/args.ts:305-308:

  -d, --data-dir <path>   Only if you want an instance SEPARATE from your
                          terminal one. Omitted by default on purpose, so
                          `paddock service` and a bare `paddock` are the same
                          ~/.paddock instance reached two ways.

The 0.68.0 changelog repeats it (packages/server/CHANGELOG.md:99): "…into a terminal are the same ~/.paddock instance reached two ways".

What the code does

resolveDataDir, packages/server/src/cli/service/index.ts:78-91:

const chosen = opts.dataDir ?? ctx.envDataDir;
if (chosen !== undefined) {
  const resolved = path.resolve(chosen);
  return { dataDir: resolved, explicit: resolved };
}
return { dataDir: defaultDataDir(ctx.homeDir), explicit: undefined };

ctx.envDataDir is process.env.PADDOCK_DATA_DIR from the installing shell, threaded at packages/server/src/cli/paddock.ts:181-183. When explicit is set, --data-dir <path> goes into the unit's argv.

So the true precedence is:

explicit --data-dir flag > PADDOCK_DATA_DIR in the installing shell > omitted

not "omitted unless you pass the flag".

The source is upfront about why, and the reasoning is sound (index.ts:82-85):

An env var set in the installing shell is an explicit choice too — but it is one the service would NOT inherit, so it gets written into the unit rather than silently dropped in favour of ~/.paddock.

That is the right call. A systemd --user unit or a LaunchAgent does not inherit your shell environment, so not baking it in would mean install silently ignored a data dir the user had clearly selected.

Failure scenario

A user with PADDOCK_DATA_DIR=/srv/paddock-data exported in one terminal — a container shell, a direnv block, a one-off PADDOCK_DATA_DIR=… paddock service install — runs install. The unit gets --data-dir /srv/paddock-data.

Later, from a normal login shell without that export, they type paddock. That instance opens ~/.paddock: no projects, no chats. They now have two instances and the --help they just read told them there would be one. paddock service status reports Data: /srv/paddock-data, which is the only place the truth is visible, and only if they think to look.

Severity

Medium. No data is lost — but "where did my projects go" is a confusing failure, and the documentation actively steers the user away from the explanation. It also matters more than it used to: --here is gone (#803), so --data-dir / PADDOCK_DATA_DIR is now the mechanism for picking which instance you get, which the 0.68 What's New entry says in as many words.

Blocks a docs claim

Yes, mildly. website/src/content/docs/guides/running-as-a-service.md describes the unit contents. A docs pass touching that page would otherwise copy the help text's promise verbatim and publish the same error on the website.

Suggested fix

Keep the behaviour; correct the words. Something like:

  -d, --data-dir <path>   Only if you want an instance SEPARATE from your
                          terminal one. Omitted by default, so `paddock service`
                          and a bare `paddock` are the same ~/.paddock instance
                          reached two ways — unless PADDOCK_DATA_DIR is set in
                          this shell, which is recorded in the unit too (a
                          service does not inherit your shell environment).

…plus the same qualification in running-as-a-service.md. Optionally, have install print the resolved data dir when it came from the environment rather than a flag, so the decision is visible at the moment it is made.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions