Skip to content

feat: Let coding agents sign in and install every plugin - #358

Merged
mattdjenkinson merged 2 commits into
mainfrom
feat/agent-login-and-plugin-install-all
Nov 6, 2026
Merged

mattdjenkinson merged 2 commits into
mainfrom
feat/agent-login-and-plugin-install-all

Conversation

@mattdjenkinson

@mattdjenkinson mattdjenkinson commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Coding agents run datumctl without a terminal. These changes let an agent set up datumctl for a user without asking them to type commands. They come from the agent setup prompt in datum-cloud/agents.datum.net#122, which currently has to work around both problems.

datumctl login

Before: after the browser sign-in, login showed an org/project picker. Without a terminal the picker failed for anyone with more than one project, and login returned before saving the session, so the sign-in was lost.

Now:

  • Context named: --project, --organization, DATUM_PROJECT or DATUM_ORGANIZATION picks the context without the picker. --project also accepts <org>/<project>. These are the existing global flags; login just never read them.
  • No terminal, nothing named: login saves the session, leaves the context unset, prints how to run datumctl ctx use <org>/<project>, and exits 0.
  • No match for the name given: login still saves the session, then exits with an error naming the value.
  • Switching accounts: if the current context belongs to a different session, it's cleared so the new session becomes active (the current context decides which session is active). A context from the same session is kept when signing in again.
  • With a terminal: picker behaviour is unchanged.

datumctl plugin install --all-available [--index <catalog>]

  • Installs every plugin in the official datum catalog, or the catalog named by --index.
  • Upgrades plugins that are behind the catalog and leaves up-to-date ones alone.
  • Skips a same-name plugin installed from another catalog or GitHub instead of replacing it.
  • Carries on past a failed plugin, lists failures at the end and exits non-zero.
  • Third-party catalogs ask first. With a catalog other than datum, it lists the plugins it would install and asks [y/N], as plugin index add does. --yes skips the prompt. With no terminal and no --yes it exits with an error and installs nothing. The official catalog, and a catalog with nothing to install, never prompt.
  • --index without --all-available is an error that points to <catalog>/<plugin>. A plugin name with --all-available is also an error.

datumctl plugin search -o json|name

  • -o json prints an array of {name, index, version, trust, description}. It prints [] when nothing matches.
  • -o name prints one plugin name per line.
  • The table output is unchanged.

Docs

README, docs/authentication.md (new "Choosing a context" section) and docs/developer/plugins.md.

Test plan

  • go test ./..., go vet ./... and gofmt pass.
  • New unit tests cover:
    • login: picking the context (by id, org/project, org only, unknown, an ambiguous display name, no terminal, a single context), reading flags vs env vars, and clearing another account's context;
    • plugins: install planning (missing, behind, up to date, other catalog, GitHub, records from before the catalog field existed), --all-available with everything up to date and with an empty catalog, the flag errors, and search -o json|name|xml.
  • Third-party confirmation tests: no answer (error suggesting --yes), n (aborts), y and --yes (go ahead), the official catalog and an up-to-date third-party catalog (no prompt), and --yes without --all-available (error).
  • Against the real catalog in a throwaway plugins folder: plugin search --index datum -o name|json listed all 9 plugins, plugin install --all-available installed all 9, and a second run reported them up to date.
  • Not yet run: a real browser sign-in with datumctl login --project <org>/<project> < /dev/null, and with no scope and no terminal.

Coding agents run datumctl without a terminal. Two things stopped them
from setting it up on their own.

datumctl login showed an org/project picker after the browser sign-in.
Without a terminal the picker failed for anyone with more than one
project, and login returned before saving the session, so the sign-in
was lost. Login now honours --project, --organization, DATUM_PROJECT and
DATUM_ORGANIZATION to choose the context without the picker. With none
of them and no terminal, it saves the session, leaves the context unset
and says how to pick one. A current context from another session is
cleared so the new session becomes active.

Installing every plugin meant parsing the search table and calling
install once per name. plugin install --all-available installs every
plugin in the official datum catalog (or --index), upgrades ones that
are behind, and skips same-name plugins from another source. plugin
search gains -o json and -o name for scripts.
ecv
ecv previously approved these changes Nov 6, 2026

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve.

Login only changes how a context is chosen; the OAuth/device flow, token storage and output are untouched, so credential handling is not weakened. --all-available loops the existing installPlugin, so every plugin still gets the index SHA256 archive check and the compatibility check, with no new trust path.

  • Login: no token is printed or written differently. saveWithoutContext saves the same config via SaveV1Beta1 and returns nil on the no-terminal path, so an agent run exits 0 with a signed-in session but no context. Scripts that assume exit 0 means "ready to run commands" will fail on the next call, not at login; the printed hint covers it.
  • Login: clearOtherSessionContext unsets the current context when it belongs to a different session. That is deliberate and tested (TestClearOtherSessionContext), but it is a visible behaviour change for anyone signing a second account in, so it deserves a line in the docs.
  • Install-all: --index acme installs every plugin from a third-party catalog in one go with no trust warning or confirmation. Single install <catalog>/<plugin> has the same shape, so this is parity, but the blast radius is larger. Archives are still SHA256-pinned by the index, so a compromised catalog is trusted wholesale.
  • Install-all: partial failure is handled (continue, list failures, exit non-zero, manifest saved only if something installed). However installPlugin writes each binary before the manifest is saved at the end, so a crash or a failed Save mid-run leaves binaries on disk with no manifest entry. Saving after each successful plugin would close that.
  • Plugins already installed from another catalog or GitHub are skipped rather than replaced, which avoids a name-shadowing takeover via --all-available. Good, and covered by TestPlanCatalogInstall.
  • Tests cover the planner, flag errors, empty catalog, up-to-date no-download, chooseContext, requestedContext and search output formats. No test drives a real mixed success/failure install loop or the manifest save.

Follow-ups:

  • Warn, or require --yes, before --all-available against a non-official catalog.
  • Save the manifest per plugin rather than once at the end.

plugin install --all-available --index <catalog> installs every plugin
in that catalog, so with a third-party catalog it now lists the plugins
it would install and asks to confirm first, as plugin index add does.
--yes skips the prompt. With no terminal and no --yes it exits with an
error instead of installing anything. The official datum catalog, and a
catalog with nothing to install, never prompt.
@mattdjenkinson
mattdjenkinson requested a review from ecv November 6, 2026 16:24
mattdjenkinson added a commit to datum-cloud/agents.datum.net that referenced this pull request Nov 6, 2026
Rely on datum-cloud/datumctl#358:

- Install plugins with `datumctl plugin install --all-available` instead
  of parsing `plugin search` output and installing one at a time.
- Run `datumctl login --project <org>/<project>` from the agent, so the
  user only approves the sign-in in their browser. Without a project,
  login signs in and the agent picks the context with `ctx use`.
- Always upgrade an existing datumctl, and fall back to the old flow
  when a flag is missing.

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve.

The new commit closes my earlier follow-up: --all-available against a third-party catalog now lists the plan and asks y/N, fails with a hint when no one can answer (script, CI, agent shell), and installs nothing on "no". The official catalog path and single installs are unchanged, and --yes without --all-available is rejected.

Follow-ups:

  • Saving the manifest once at the end, rather than per plugin, is still open from the earlier review.

@mattdjenkinson
mattdjenkinson merged commit c75e71b into main Nov 6, 2026
2 checks passed
@mattdjenkinson
mattdjenkinson deleted the feat/agent-login-and-plugin-install-all branch November 6, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants