Skip to content

feat: deploy-by-reference via native harper CLI (prototype / draft) - #118

Open
dawsontoth wants to merge 4 commits into
mainfrom
claude/deploy-by-ref-native
Open

feat: deploy-by-reference via native harper CLI (prototype / draft)#118
dawsontoth wants to merge 4 commits into
mainfrom
claude/deploy-by-ref-native

Conversation

@dawsontoth

@dawsontoth dawsontoth commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Draft / prototype. This is what create-harper's deploy scaffolding looks like once native harper CLI support lands. It deliberately uses CLI features that aren't released yet, so it can't merge until they do — see Blocked on below.

What this shows

The end-state of the deploy-by-reference switch (create-harper#117): scaffolded projects deploy by reference (the Harper cluster clones a pinned commit over SSH) with no per-project scripts.

  • package.json: deployharper deploy by_ref=true restart=true replicated=true; deploy:setupharper deploy setup=true.
  • Centralized GitHub Actions workflow at .github/workflows/deploy.yaml — also fixes a latent bug: templates shipped a singular _github/workflow/ that GitHub never runs; now workflows/ (plural). Tag- and dispatch-triggered.
  • .env carries only CLI_TARGET; credentials come from harper login (local) or GitHub Actions secrets CLI_TARGET / HARPER_CLI_USERNAME / HARPER_CLI_PASSWORD (CI).
  • README "Deployment" sections rewritten around the reference model + rollback.

Relationship to the ships-today version

The interim version that works with the currently released CLI carries scripts/deploy.mjs + scripts/setup-deploy.mjs (the logic lives in the project until the CLI can do it natively). It's on branch claude/harper-deployment-path-dd2495. This PR is the same feature with those scripts folded into the CLI.

Blocked on (must release first)

Tracks create-harper#117. Rollback: HarperFast/harper#641.

Notes

  • deploy:setup spelling (setup=true vs --setup vs a dedicated harper add-deploy-key) is TBD per harper#1778; this PR uses setup=true to match the CLI's key=value arg model.
  • npm test (213 tests) green; dprint + oxlint clean.

🤖 Generated with Claude Code


Related — deploy-by-reference effort

  • HarperFast/harper#1849 — two-phase stage/activate + revert_component
  • HarperFast/harper#1850harper deploy by_ref=true (deploy by git reference)
  • HarperFast/harper#1851harper deploy setup=true (client-side sealed deploy credential)
  • HarperFast/harper#1876 — CI token auth + harper login --for-ci
  • HarperFast/harper-pro#594add_ssh_key generate=true (cluster-side keygen)
  • HarperFast/create-harper#118 — scaffolds this flow
  • HarperFast/documentation#599 — two-phase deploy docs
  • HarperFast/documentation#616 — by-reference / sealed-credential / CI-auth docs

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates the deployment process across multiple project templates to deploy "by reference" using the native harper CLI. It adds a new GitHub Actions workflow (deploy.yaml), updates package.json scripts to include deploy and deploy:setup, and updates the documentation in README.md files. Feedback on these changes highlights that the template-early-hints template was only partially updated, missing changes to its package.json and README.md. Additionally, installing the harper CLI globally in the workflow without a version pin could introduce breaking changes in the future, and the duplication of the deploy.yaml file across all template directories should be addressed by dynamically copying it from a centralized location.

Comment thread template-early-hints/_github/workflows/deploy.yaml Outdated
Comment thread templates-shared/all/_github/workflows/deploy.yaml Outdated
Comment thread templates-shared/all/_github/workflows/deploy.yaml
dawsontoth and others added 4 commits July 29, 2026 14:19
Templates deploy by *reference* (the Harper cluster clones a pinned commit over SSH) with no per-project scripts: deploy -> `harper deploy by_ref=true restart=true replicated=true`, deploy:setup -> `harper deploy setup=true`. Centralized GitHub Actions workflow (.github/workflows/deploy.yaml — also fixes the singular workflow/ -> workflows/ path bug so GitHub runs it); tag+dispatch triggered. .env carries only CLI_TARGET (creds via harper login / CI secrets). README deployment sections rewritten around the reference model.

End-state assuming native CLI support has landed: harper#1777 (by_ref), harper#1778 (deploy setup), harper-pro#570 (add_ssh_key generate). Tracks create-harper#117. DRAFT until those release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rly-hints

Pin the workflow's global install to `harper@^5.2.0` (the 5.2 line where deploy-by-reference lands; blocks a breaking 6.x bump) instead of unpinned latest. Exclude template-early-hints (a legacy harperdb EdgeWorker example, not published via npm create harper) from the deploy migration: remove the stray _github workflow it got via fan-out, and filter _github out of applySharedTemplates for it so it isn't re-added (it keeps every other shared file).

The per-template deploy.yaml duplication is intentional (templates-shared/README.md: shared files are committed into each template for discoverability + wholesale-copy scaffolding), so it's left as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Aligns the scaffold with where the deploy design landed (harper#1799 in-memory git-host credential + client-side-sealed durable tokens) instead of SSH deploy keys: deploy -> `harper deploy by_ref=true credential=github.com ...` (git+https ref + a sealed-token credential reference the cluster resolves at clone time; public repos drop credential=github.com). deploy:setup -> `harper deploy setup=true` seals a durable GitHub/npm token locally with the cluster's public key and stores only ciphertext. README rewritten around the sealed-token flow; the workflow no longer handles any token itself.

Depends on harper#1777 (by_ref git+https + credential), harper#1778 (deploy setup), harper#1799.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follows main's Next.js templates and harper#1876's CI credential flow.

Next.js stays on deploy-by-payload, deliberately. By-reference means the
cluster clones the repo and builds on the node, which Next.js can't do: `.next`
is gitignored, so a git reference carries no build output, and an on-cluster
build currently fails outright (Turbopack crashes in a Harper worker thread,
HarperFast/nextjs#57; a webpack build overruns the component-load timeout,
HarperFast/nextjs#58). They keep `next build && harper deploy_component .`
until those land. `applySharedTemplates.js` records why they're absent from the
fan-out, so their omission reads as a decision rather than an oversight.

They do get the `_github/workflow/` → `_github/workflows/` fix this PR makes
everywhere else — GitHub only runs workflows from the plural directory, so the
one they shipped never triggered — plus their own payload-deploy workflow with
the same auth wiring.

CI now authenticates with a token instead of a password. The workflows consume
HARPER_CLI_TARGET + HARPER_CLI_REFRESH_TOKEN (harper#1876) rather than
HARPER_CLI_USERNAME/HARPER_CLI_PASSWORD, and the docs point at the pipe that
sets both without the token ever reaching the screen or shell history:

  harper login --for-ci | gh secret set --env-file -

template.test.js asserts the deploy model per template, with the payload-based
ones as an explicit allow-list — a newly added template fails the by-reference
assertions until it's either wired up or added there with a reason, so it can't
silently opt out. Verified by flipping the list: exactly the two Next.js
templates fail, confirming the assertions actually run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dawsontoth
dawsontoth force-pushed the claude/deploy-by-ref-native branch from 6199d28 to f352445 Compare July 29, 2026 18:31
@dawsontoth

Copy link
Copy Markdown
Contributor Author

Rebased onto main (v1.11.2) — clean, no conflicts. Two things changed in the meantime that this needed to absorb:

1. Next.js templates landed on main, and they can't use deploy-by-reference.

By-reference means the cluster clones the repo and builds on the node. Next.js can't do that today: .next is gitignored (so a git reference carries no build output) and an on-cluster build fails outright — Turbopack crashes inside a Harper worker thread (nextjs#57) and a webpack build overruns the component-load timeout (nextjs#58). That's exactly why ded2190 re-instated prebuilt: true.

So they stay on deploy-by-payload (next build && harper deploy_component .), and applySharedTemplates.js now records why they're absent from the fan-out — otherwise the omission reads as an oversight and someone "fixes" it into a broken deploy.

They do get the _github/workflow/_github/workflows/ fix this PR makes everywhere else. GitHub only runs workflows from the plural directory, so the one they shipped never triggered; they now have a payload-deploy workflow in the right place with the same auth wiring.

2. CI auth moved from password to token (harper#1876).

The workflows now take HARPER_CLI_TARGET + HARPER_CLI_REFRESH_TOKEN instead of HARPER_CLI_USERNAME/HARPER_CLI_PASSWORD, and the READMEs point at the pipe that sets both without the token ever reaching the screen or shell history:

harper login --for-ci | gh secret set --env-file -

Testing. template.test.js now asserts the deploy model per template, with the payload-based ones as an explicit allow-list — a newly added template fails the by-reference assertions until it's either wired up or added there with a reason, so it can't silently opt out.

Worth flagging: template.tests/template.test.js is dormantvitest.config.js includes only template.tests/staticConfig.test.js, so these assertions don't gate PRs. I ran it directly (12/12 pass) and confirmed they aren't vacuous by flipping the allow-list to empty: exactly the two Next.js templates fail. Enabling it in CI is a separate call — it scaffolds all 12 templates — so I left the config alone.

dprint check, oxlint, and npm test (216) are clean.

@kriszyp kriszyp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good. I kinda did two GPT reviews, which is probably a bit excessive, but hopefully helpful:
Overall, this is well aligned with the deployment guidance. The immutable-SHA reference model, cluster-stored clone credential, token-based CI authentication, and payload exception for Next.js all look right. It effectively implements the newer workflow from documentation#616 rather than documentation#594’s lower-level curl examples.
I have two changes before approval:
The generated commands use restart=true with replicated=true. Documentation#594 recommends restart=rolling for cluster deployments and reserves restart=true for single-node/dev use. Since the scaffolded workflow targets Fabric clusters, can we default its deployment to restart=rolling, or document why an immediate cluster-wide restart is intended?

The READMEs describe HARPER_CLI_REFRESH_TOKEN as long-lived but omit two operational constraints: CI should use a dedicated user because issuing another refresh token invalidates the existing one, and the default refresh-token lifetime is 30 days. Please add a short warning so generated pipelines do not unexpectedly break after a local login or token expiry.

The PR description also needs refreshing: it still mentions SSH, password-based CI authentication, and the superseded dependency PR numbers, while the implementation now uses git+HTTPS, sealed tokens, and harper#1850/#1851/#1876.
Finally, this should remain blocked until harper#1850 and harper#1851 land in a released CLI. The current CI proves the templates generate correctly, but it cannot exercise those unreleased commands.
🤖 Reviewed with GPT 5.6

- name: Set up Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
cache: 'npm'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This now makes the previously inert workflow run, but it is hard-coded to npm even though create-harper detects and installs with pnpm, Yarn, Bun, and Deno too. For example, a project created with pnpm create harper commits pnpm-lock.yaml, so setup-node's npm cache cannot resolve a package lock and the following npm ci fails; the tag workflow never reaches tests or deploy. Please generate the cache/install/run setup from the detected package manager (and apply the equivalent fix to both standalone Next.js workflows), or deliberately generate an npm lockfile and document npm-only CI. Please also exercise at least one non-npm user agent in the scaffold test so this path cannot regress.

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