Skip to content

docs(sdk-cli): add spec for dotcms agent setup - #37392

Open
fmontes wants to merge 9 commits into
mainfrom
fmontes/37390-dotcms-agent-setup
Open

docs(sdk-cli): add spec for dotcms agent setup#37392
fmontes wants to merge 9 commits into
mainfrom
fmontes/37390-dotcms-agent-setup

Conversation

@fmontes

@fmontes fmontes commented Sep 3, 2026

Copy link
Copy Markdown
Member

Spec-Kit PR 1 of 2 — spec.md only, no implementation. Approve this and PR 2 branches off it; you're not blocked on this merging.

Refs #37390

What this specifies

One command that replaces the four manual steps needed to point an AI coding agent at a dotCMS instance — find the admin panel, mint a token by hand, hand-edit whichever config file your editor reads, install the skills separately.

npx dotcms agent setup

It asks for a URL, credentials, and which editors to wire up; mints a token and verifies it before touching any file; writes the dotCMS MCP server into each editor's own config by merging rather than overwriting; installs the skills; and launches the server to confirm it responds before calling itself done.

Give it a URL and one auth mode up front and it runs unprompted. Targets default to every detected editor, scope to the folder you ran it in.

Seven targets: Claude Code, Cursor, VS Code/Copilot, Codex, Antigravity, Devin, OpenCode.

62 functional requirements · 11 success criteria · 4 user stories · 9 recorded clarifications.

What to review for

Is this the right problem, scoped right, with measurable criteria? The calls worth arguing with:

  • Scope is agent setup alone. status and remove were specified, then cut — re-running setup replaces a stale entry, and removing one is a hand edit of a single named key. create-app stays where it is; the dotCLI port isn't started. The agent sub-command group is the seam all of these fold into later. Right line?
  • Folder is the default scope, not the user account. One dotcms entry per config file; a second instance means a second folder. This makes the credential-into-a-repo path the common one, so FR-023 compensates: --yes takes the safe answer on the .gitignore offer instead of skipping it. Enough?
  • Two mutually exclusive auth modes. --user/--password mints a token; --authToken uses one you have. Passing both is a usage error, not a silent precedence rule — silent preference hides a mistake in exactly the scripted runs these flags exist for.
  • Token verification is unconditional and ordered first (FR-008/a/b/c). Every credential source is checked against the instance before a single file is opened; on failure nothing is written — no file, no directory, no skills install — and --yes/--force cannot disable the check.
  • The run proves the agent connects, not just that the token is valid (FR-024a–e). After writing, setup launches the configured server and confirms it lists tools. A non-start reports distinctly from a credential failure, keeps the written configs, and exits non-zero.
  • Partial failure continues (FR-020a–d). One unwritable target doesn't stop the others, nothing is rolled back, per-target reasons are reported, and any failure exits non-zero so CI catches it.

Three risks the spec accepts on purpose

Each is recorded in Assumptions with its reasoning rather than left as a silent gap:

  1. A password passed as a flag is visible in the process list and shell history — the same exposure the spec refuses for the token. Needed for CI. Mitigated with an env-var alternative, a --help warning, and never persisting it.
  2. A failed run can orphan a minted token. Minting precedes writing, so a run that mints and then fails leaves a real 365-day token nobody saw. The fix that actually recovers it is printing it, which contradicts FR-022 — a rule User Story 3 rates P1. Orphans expire within a year and the failure needs an already-broken environment.
  3. Concurrent writes aren't solved. A running editor may rewrite its config and drop the entry. No locking; re-running is cheap and idempotent.

ADR gate

ADR-0019 (accepted) governs this package and produced two conflicts. The secrets ADRs were checked and rejected explicitly — they cover AWS Secrets Manager for Kubernetes, not a CLI writing to a developer's own disk.

  • Complied with. ADR-0019 requires SDK packages to warn when the instance is older than the tool. Added as FR-005a, reusing the response already fetched for the reachability check, so it costs no extra request.
  • Justified deviation. The written config references the MCP server unpinned (@latest), against the ADR's pin-exact-versions guidance. @dotcms/mcp-server is at 0.1.1, is not date-lockstep, and has no release workflow anywhere in .github/ — there is no CLI-matched version to pin to. Recorded in the plan's Complexity Tracking.

Verified while specifying, worth a look

  1. The release pipeline needs a change the original design assumed it didn't. deploy-javascript-sdk/action.yml publishes generically, but its "already published" guard is npm view "@dotcms/${dir}@${version}" — scope hardcoded, name from the directory. An unscoped dotcms package can never match it: the first publish succeeds, then any re-run tries to re-publish an existing version and fails the release step. Captured as FR-034.
  2. dotCMS/agent-toolkit is now public (verified, including an unauthenticated clone). That was the feature's one hard release gate; it's cleared.
  3. Repurposing the dotcms npm name replaces a dormant 0.0.21 library. Unpinned consumers break at first publish — confirm download volume before shipping.

Open items carried into planning

None block approval; all are in Assumptions.

  • VS Code/Copilot skills placement is unverified — FR-027 requires the summary to report honestly rather than claim success
  • Antigravity's global config path is documentation-sourced, not observed
  • chmod 0600 is a no-op on Windows, so FR-021 is POSIX-only and the summary must say when permissions couldn't be applied

Not in this PR

plan.md, tasks.md, and any code — PR 1 carries spec.md alone. Note that this repo gitignores plan.md / research.md / quickstart.md as process artifacts, so the design work lands in PR 2 as data-model.md and contracts/.

🤖 Generated with Claude Code

Spec-Kit PR 1 of 2 for #37390 — spec only, no implementation.

Specifies a `dotcms agent setup` command that collapses the four manual
steps needed to connect an AI coding agent to dotCMS (find the admin
panel, mint a token, hand-edit an IDE config, install skills) into one
command across seven agent targets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

❌ Linked Issue Needs Team Label

This PR is linked to issue #37390, but that issue has no Team : * label. Every linked issue must be owned by a team for tracking and triage.

How to fix this:

Apply a Team : * label to the linked issue (e.g., Team : Scout, Team : Platform, Team : Falcon, Team : Maintenance). Then push a new commit or edit the PR description to re-run this check.


This comment was automatically generated by the issue linking workflow

@claude

claude Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @fmontes's task in 1m 47s —— View job


Spec review — dotcms agent setup

This is a Spec-Kit PR 1 (spec only, no code), so I reviewed spec.md for scope, measurability, internal consistency, and I verified the load-bearing pipeline claim against the repo. It's a strong, unusually thorough spec. The scoping calls (setup-only, folder-default, mutually-exclusive auth, unconditional token verification ordered first, prove-the-agent-connects) are all sound and internally justified. A few things to fix or confirm before this becomes the frozen contract for PR 2.

Verified

  • FR-034 is correct — and the failure has two causes, not one. I read .github/actions/core-cicd/deployment/deploy-javascript-sdk/action.yml. The idempotency guard at line 184 is npm view "@dotcms/${sdk}@${RELEASE_VERSION}" — scope hardcoded, name from the directory basename, exactly as the spec says. But note the publish at line 188 (npm publish) takes the package name from each package's own package.json name field, not from @dotcms/${sdk}. So for an unscoped dotcms package the two diverge: publish targets dotcms, the guard checks @dotcms/dotcms (which never exists) → re-run always attempts a re-publish → hard 403 → release step fails. The version-rewrite loop (lines 81-89) has the same scope assumption for sibling deps. The spec's mechanism is right; I'd fold the "publish name comes from package.json, so the guard and the publish target are keyed differently" detail into the FR-034 assumption so the plan fixes the divergence, not just the one npm view line.

Findings

  • 🟡 Medium: spec.md:197 / spec.md:201FR number collision. FR-024 (warn when a folder-scoped file is conventionally committed to VC, under Handling the token) and FR-024aFR-024e (connection confirmation, under Confirming the agent actually connects) are unrelated requirements. The -a suffix convention everywhere else in this spec means "refinement of the base number" (see FR-003/003a, FR-008/008a). Here it collides two distinct concerns onto 024, which will confuse task traceability in PR 2. Renumber the connection-confirmation block (e.g. FR-035…) or renumber the VC-commit warning.

  • 🟡 Medium: spec.md:154FR-005a only warns when the instance is older than the tool. ADR-0019 is date-lockstep, so a tool older than the instance is equally a mismatch (the developer's npx dotcms is stale). The spec is silent on that direction. If "older instance" is the only case worth warning on by intent, state that explicitly in FR-005a so it reads as a decision rather than a gap; otherwise it's an uncovered case. Non-blocking but cheap to pin down now.

  • 🟡 Medium: spec.md:152-154, spec.md:184, spec.md:222out-of-order suffixed requirements. FR-005b precedes FR-005a; FR-020e precedes FR-020aFR-020d. Cosmetic in prose, but this spec generates tasks.md — reviewers and the task generator read top-to-bottom, and a suffix that sorts after its siblings but appears before them is an easy source of missed coverage. Reorder to a,b,c,….

Questions on the scoping calls you flagged

  • Scope = agent setup alone. Agreed this is the right line. status/remove folding into the agent group later is clean, and "re-run replaces the stale entry" (FR-017, US2) genuinely covers the repoint case. The one thing re-run does not recover is the orphaned token from a prior failed run — which you've already accepted in Assumptions. Consistent.
  • Folder as default scope + FR-023 forcing the safe answer under --yes. This is the right call precisely because it inverts the usual --yes semantics for the one prompt where "skip it" is the dangerous default. FR-023/023a/024 cover VC-tracked, untracked, and conventionally-committed files respectively — that's the full matrix. Good.
  • Two mutually-exclusive auth modes as a usage error (FR-003b). Correct, and reporting the input the developer actually used (option vs env var) rather than a canonical flag name is a nice touch that most specs miss.
  • Token verification unconditional and ordered first (FR-008/a/b/c). The "nothing written on failure, not skippable by --yes/--force" invariant is the strongest part of the spec. FR-008c's "config-skip is the only way to end a run without verification" is coherent — nothing written means nothing to verify against.

Everything else (partial-failure continues + non-zero exit, prove-the-agent-connects distinct from token validity, the three consciously-accepted risks) is well-reasoned and self-consistent. No blocking issues — the three Medium findings are contract-hygiene fixes worth making before PR 2 branches, not reasons to withhold approval.

Note: the unrelated CI check failing on this PR is the linked-issue-needs-Team-label workflow (#37390 has no Team : * label) — nothing in the spec itself.
· fmontes/37390-dotcms-agent-setup

…semantics

Addresses two gaps found reviewing the spec.

Setup proved the token was valid but never that the MCP server actually
starts, so a stale package cache or unsupported runtime would produce a
green summary and a broken agent. Confirmation now runs by default
(FR-024a-e, SC-002a): it launches the server as configured, confirms it
reports its tools, and reports a non-start distinctly from a credential
failure without rolling back written configs.

Writing spans up to seven files and nothing said what happens when one
fails after others succeeded. Setup now continues, reports per-target
outcomes, and exits non-zero on any failure (FR-020a-d, SC-006a).

Also: FR-013 annotated as a structural constraint rather than a testable
requirement, FR-023a covers project scope outside version control,
concurrent writes documented as a known limitation, and SC-001/SC-002
labelled design intent rather than automated gates.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Records four /speckit-clarify decisions.

Folder is now the default scope, not the user account: one dotcms entry
per config file, multiple instances via different folders. Because that
makes the credential-into-a-repo path the default, FR-023 is strengthened
so assume-yes takes the safe answer on the gitignore offer rather than
skipping it.

status and remove are cut from this release; only agent setup ships. User
Story 5 withdrawn, FR-029/030/031 and SC-007/008 retired, and everything
that leaned on those commands reworded. The agent sub-command group stays
as the seam for adding them later.

The written entry references the latest published server rather than
pinning a version (FR-020e).

The instance address plus one auth mode are the only required inputs;
supply both and setup completes without prompting, terminal or not
(FR-003i-l). Targets default to every detected editor and scope to the
folder, so neither blocks a run. assume-yes and force govern confirmation
prompts only and can never suppress a prompt for a missing required input.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
No diagnostic mode ships — no verbose flag, no debug output, no log file.
Recorded as a deliberate decision rather than an omission, with FR-032a
requiring every failure message to be self-sufficient, since "re-run with
more detail" is not available as a remedy.

Terminology normalized to "token" for the thing minted, supplied, verified
and written; a username and password are named as such rather than called
"credentials". No behavior change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The /speckit-plan ADR gate found that ADR-0019 (accepted) requires SDK
packages to compare the instance's dotCMS version against their own and
warn, fail-open, when the instance is older. dotcms ships from libs/sdk/,
is published by the SDK release pipeline, and is date-lockstep versioned,
so the requirement applies.

FR-005a reuses the response already fetched for the reachability check,
so it costs no additional request.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Minting happens before configurations are written, so a run that mints
and then fails leaves a real 365-day token on the instance that was never
displayed and never recorded. Re-running mints another, and nothing
identifies or revokes them.

Accepted rather than mitigated. The alternative that actually recovers
the credential is printing it, which contradicts FR-022 -- a rule User
Story 3 rates P1. Orphans expire within a year and the failure requires
an already-broken environment.

Recorded in Assumptions rather than left silent, so a reviewer sees the
trade-off instead of rediscovering it later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FR-007 gave three attempts when a username and password fail to mint, but
said nothing about a supplied token that fails to verify. Running the CLI
by hand showed why that gap matters: one mistyped paste ended the run.
The two are the same user error and now share the retry.

FR-007a limits it to rejections -- an unreachable instance or a TLS error
is not retried, because retyping a credential cannot fix it. FR-007b
keeps a non-interactive run failing at the first attempt, since a script
has nowhere to retype.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…alive

FR-005 only required that something answer. A proxy, CDN error page or
unrelated app answering 200 passed the check, and setup would write a
configuration pointing at it -- producing an agent that fails every call
later with nothing to explain why.

FR-005b requires confirming the response is a dotCMS configuration, and
reporting a non-dotCMS host distinctly from an unreachable one. The two
have different remedies, so collapsing them costs the developer the one
piece of information that helps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ng or missing

FR-003b said the conflict error must name the conflicting "options". The
conflict can come from environment variables, and reporting --authToken
to someone who set DOTCMS_AUTH_TOKEN sends them hunting for a flag they
never typed. Now: name the inputs actually used.

FR-003c1 is new. Nothing said the skip options are independent, and the
implementation read --skip-mcp as "skip everything downstream", so it
silently installed no skills and printed no summary. The only permitted
implication is FR-024b's: with nothing written there is no configuration
for the connection check to prove.

FR-016a is new. "Preserves everything else exactly" was read as data
only, so the TOML writer re-serialized a parsed document and deleted the
developer's comments. For a hand-maintained format that is data loss even
though every value survives.

Not changed, because the spec was already right and the code was not:
FR-021 says "any directory setup CREATES" (the implementation re-chmodded
pre-existing ones), FR-023 says "every file it PLACED A TOKEN INTO" (it
named files that were only skipped), and FR-024b already covered the
connection check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant