Skip to content

docs(cli): install, link flow, CI usage, exit codes and troubleshooting - #352

Draft
DevQwinB wants to merge 2 commits into
blockchain-maxis:mainfrom
DevQwinB:docs/cli-guide
Draft

docs(cli): install, link flow, CI usage, exit codes and troubleshooting#352
DevQwinB wants to merge 2 commits into
blockchain-maxis:mainfrom
DevQwinB:docs/cli-guide

Conversation

@DevQwinB

Copy link
Copy Markdown

closes #288

Draft, and stacked on #349 (#277, the database precondition), because that PR creates docs/CLI.md for its cross-reference and this one expands it. The diff includes #349 until it lands. Also a draft because the CLI itself is still being built — see What this documents below.

Change

docs/CLI.md, from a 65-line stub to the full guide: install and npx usage, the link flow, keystore identity selection across platforms, configuration precedence, CI usage, self-hosted baseUrl, --json, the exit-code table, and a symptom → cause → fix table.

The link flow, as five steps that each prove something

The issue asks for "the full link flow with what each step proves", so the flow is a table with that as its own column rather than a narration:

Step Proves
Preflight The signer exists and is reachable before anything user-visible starts
Pair The pairing is bound to this process; the code is useless to anyone who did not start it
Approve You control the handle — browser session, never the CLI's business
Sign You control the wallet — signature over a challenge scoped to this pairing
Complete Both proofs arrived in one session, so handle and wallet are the same person

Steps 3 and 4 are documented as deliberately separate: the handle proof happens where the session lives, the wallet proof where the key lives, and neither component sees the other's secret. That is the design, and a reader who does not understand it will file the split as friction.

Two things stated rather than glossed

The stellar CLI dependency is explained, not just listed. It is the reason the Signet CLI never holds secret key material at all — not in memory, argv, logs, or a crash dump — and it is why hardware signing and OS secure-store work for free. A prerequisite line would leave a reader thinking it is incidental.

The keystore section says what it is for. Per-platform paths are documented, prefixed with "you do not need to know this" — stellar owns the format and the CLI never reads it — followed by the consequence that actually bites: an identity created as your user is invisible to root, another user, or a container that does not mount the directory. That is the usual cause of "no identity found" on a machine where stellar keys ls plainly works.

A discrepancy I did not resolve silently

#288's acceptance says "CI usage with SIGNET_DEPLOY_KEY". #254 specifies passing --sign-with-key through to stellar tx sign, which already reads STELLAR_SIGN_WITH_KEY.

The doc reconciles them rather than picking one quietly: the CI example stores the secret as secrets.SIGNET_DEPLOY_KEY and exposes it as STELLAR_SIGN_WITH_KEY, with a note that the CLI reads the latter because introducing a second name for the same secret means copying it between variables in every pipeline.

env:
  STELLAR_SIGN_WITH_KEY: ${{ secrets.SIGNET_DEPLOY_KEY }}
run: npx @signet/cli link --no-browser --json

If you would rather the CLI read SIGNET_DEPLOY_KEY directly, say so and I will flip the doc — but that decision belongs to #254, and it should be made rather than inherited from whichever document was written last.

The section also flags that the approval step still needs a human in a browser once: CI usage is for re-linking and verification, not unattended bootstrapping, which would defeat the handle proof.

Exit codes and troubleshooting

Nine codes from #259's classes, each with a "retryable" column — 5 network, 6 timeout, 9 no database are the only ones worth retrying automatically, and 9 is explicitly not the developer's to fix.

The troubleshooting table covers every symptom the issue names — no identity, browser will not open, loopback blocked, approval timeout, already linked, no database — in TROUBLESHOOTING.md's existing symptom → cause → fix shape. Loopback blocked gets its own section, since it is the failure that presents as "nothing happened": it is invisible in local development (localhost → localhost is not a public → private transition) and gives a concrete way to confirm it from the browser console rather than guessing.

What this documents

The CLI is still being built (#251 and the issues after it), so this describes designed behaviour and names the issue that lands each part#253 identity, #254 CI signing, #257 browser fallback, #259 exit codes, #262 config, #264 --json, #272 loopback, #293 npx, #297 version check. The status note at the top says exactly that.

That makes this a contract those issues are implemented against rather than a description of something shipped. If any of them lands different behaviour, this file is the thing to correct — which is preferable to it being written afterwards from whatever the code happened to do.

The one part enforced on main today is the database precondition, which comes from #349.

Verification

Documentation only. prettier --check clean. Every issue reference and internal anchor checked by hand.

Wallet links are Wallet rows in Postgres. The read path degrades
gracefully with no DATABASE_URL — safeDbProfile and safeDbOperations
return null and the caller falls through to a chain read, then to the
curated demo profiles — and that is right for reads. It is exactly wrong
for writes: the same fall-through makes a link appear to succeed while
persisting nothing. The developer believes they are linked, the CLI
believes it, and the failure surfaces later from some unrelated command
that needed the binding.

Add the write-path counterpart next to those helpers in lib/profiles.ts:
isDatabaseConfigured, a typed DatabaseRequiredError carrying
isConfigurationError, and requireDatabase. Only configuration is
checked, not reachability — an unreachable database is a different
failure with a different fix, and calling it "not configured" sends an
operator to the wrong runbook.

POST /api/cli/pair/complete checks the precondition first, before the
body and before any signature: if the result cannot be stored, nothing
else about the request matters. It answers 503 rather than a 4xx because
nothing the caller sent is wrong and nothing they can do to their own
account changes it, and carries isConfigurationError so a client can
classify it without string-matching prose. Pairing verification itself
is blockchain-maxis#268's; this route returns 501 once the precondition passes rather
than pretending to complete a pairing it has not verified.

/link reads the same signal server-side, so the page and the API cannot
disagree, and disables approval with an explanation before the developer
signs something that cannot be stored.

docs/CLI.md documents the dependency, what each surface reports, and how
an operator fixes it, cross-referenced from ENVIRONMENT.md and blockchain-maxis#191.
docs/ covers deployment, environment, indexer, registry integration, demo
data and troubleshooting. Terminal linking — the path that produces a
real career record — was undocumented, and it spans a CLI, a browser, a
keystore and a loopback port. Every one of those is a place a developer
gets stuck.

Documents install and npx usage, the link flow as five steps each stating
what it proves, keystore identity selection across platforms, CI usage,
self-hosted baseUrl, --json, the exit-code table, and a symptom → cause →
fix table following TROUBLESHOOTING.md's existing shape.

Two things are stated rather than glossed. The stellar CLI dependency is
explained as the reason Signet never holds secret key material at all,
rather than listed as a prerequisite. And the browser and wallet proofs
are described as deliberately separate: the handle proof happens where
the session lives, the wallet proof where the key lives, and neither
component sees the other's secret.

The CI section documents STELLAR_SIGN_WITH_KEY as the variable actually
read, with SIGNET_DEPLOY_KEY shown as the secret name a pipeline stores
it under. Issue 288's acceptance names SIGNET_DEPLOY_KEY directly; 254
specifies passing through to stellar tx sign, which already honours
STELLAR_SIGN_WITH_KEY. Introducing a second name for the same secret
would mean copying it between variables in every pipeline, so the doc
reconciles the two rather than picking one silently.
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@DevQwinB Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

@DevQwinB is attempting to deploy a commit to the blockchainmaxis-8449's projects Team on Vercel.

A member of the Team first needs to authorize it.

@netlify

netlify Bot commented Aug 30, 2026

Copy link
Copy Markdown

Deploy Preview for stellar-signet ready!

Name Link
🔨 Latest commit 75e26b9
🔍 Latest deploy log https://app.netlify.com/projects/stellar-signet/deploys/6a946f4fe6d49500089f1441
😎 Deploy Preview https://deploy-preview-352--stellar-signet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

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.

docs/CLI.md — install, link flow, CI usage, troubleshooting

1 participant