pub const LONG_ABOUT: &str = r#"nd — the notdouble CLI.
Push and pull whole vibecoded projects to/from a notdoublehub server.
Projects carry rich, searchable metadata (descriptions, keywords, code
keywords, vibe log) stored in a notdouble.toml manifest. The CLI is
designed to be driven by an llm as much as a human.
TYPICAL WORKFLOW
nd init [--guess] create notdouble.toml (--guess prefills from
Cargo.toml/package.json/pyproject/go/README/git)
nd validate check the manifest (and get tips)
nd upload [--specs] pack + push (auto create/update; --specs
attaches machine specs without asking)
nd search "discord bot" find projects by any keyword
nd info <slug> full metadata + file list for a project
nd download <slug> pull a project's full source
nd run <slug> cache + execute a project's `run` command
nd doubles <slug> projects that look like this one
nd review <slug> -m "..." tell everyone how it went after trying it
nd update <slug> post a maintainer update (changelog entry)
nd update-nd replace nd itself with the latest from the hub
CONFIG
--server and --token are global flags: they work on any subcommand,
in any position. precedence: flag > env (ND_SERVER / ND_TOKEN) >
~/.config/notdouble/config.toml > https://notdouble.com
for a local dev hub: nd --server http://localhost:8080 upload
Run `nd llmhelp` for a compact guide written for llm agents.
Every subcommand also accepts -h/--help."#;
pub const LLM_GUIDE: &str = r#"nd — notdouble CLI (compact guide for llm agents)
==================================================
WHAT
`nd` pushes/pulls whole projects to/from a notdoublehub server.
Projects carry rich metadata (descriptions, keywords, code keywords,
vibe log) that powers search. The manifest `notdouble.toml` lives in
the project root; unknown fields are preserved, so extra metadata is
always safe to add.
UPLOAD A PROJECT
1. cd <project-dir>
2. nd init # writes notdouble.toml + .ndignore
# (.ndignore is seeded from .gitignore)
3. edit notdouble.toml:
name required; becomes the url slug (my-app -> /p/my-app)
description one-liner shown on cards
llm_description 1-3 sentences for humans + llms; main search field
keywords topic words ("todo", "bot", "automation")
code_keywords tech words ("rust", "axum", "react")
languages, license, author, install, run, entry_points
[vibe] model + prompt_summary
4. nd validate # sanity check + tips
5. nd upload # packs the dir to tar.gz (ignores .git,
# target, node_modules, .env, etc; extra
# rules in .ndignore) and pushes.
# auto-creates OR updates by slug.
DOWNLOAD A PROJECT
1. nd search "<words>" # matches name/description/llm_description/
# keywords/code_keywords/languages/author
2. nd info <slug> # full metadata + file list (use --json)
3. nd download <slug> [dest] # extracts full source (default ./<slug>)
4. TRY IT, then tell everyone how it went:
nd review <slug> --verdict works -m "built clean, ran fine"
nd review <slug> --verdict issues -m "cargo build ok but ..."
nd review <slug> -m "..." # verdict: notes
echo "..." | nd review <slug> # text from stdin
verdicts: works | issues | broken | notes
read reviews: nd reviews <slug> (or GET /api/projects/<slug>/reviews)
FINDING SIMILAR PROJECTS ("doubles")
GET {server}/api/projects/<slug>/similar returns close matches with
the exact tags they share — useful to avoid rebuilding something that
already exists (or to find code to steal. politely.)
RELEASE HINTS
nd bump [--patch|--minor|--major] one-liner version bump
upload posts a release note on any version change (0.0.1 bumps fine)
binary artifacts (.apk/.exe/.dmg/...) in the tree land on the releases
tab and upload --dry-run --json lists them pre-push
big-upload guard: >2000 files or >100MB refuses without --yes; nd pack
--summary + pack --explain keep the .ndignore loop sane
RUNNING
nd run [ref] [args] run in the current project dir, or fetch+cache a ref
nd run prefers a bundled bin/<slug>-<os>-<arch> binary when one ships
(same convention the nd project uses); otherwise it runs the manifest's
`run` command. force with --bin (require the binary) or --shell.
CONVENTIONS (optional, privacy-friendly)
`nd upload` can attach machine specs (os, cpu, ram, gpu — detected
via nvidia-smi / rocm-smi / lspci) to a project:
--specs include without asking
--no-specs never include
neither asks y/n when interactive; non-interactive = no
UPDATE ND ITSELF
nd update-nd pulls the 'nd' project from the hub, checks
bin/nd-<os>-<arch> inside the bundle runs,
then atomically replaces this binary
nd update-nd --force even when versions already match
first install: curl -fsSL https://notdouble.com/install.sh | sh
(windows: irm https://notdouble.com/install.ps1 | iex)
(or cargo install from source); then keep current with update-nd
prebuilt binaries live in the 'nd' project bundle: bin/nd-<os>-<arch>
FORKS & MERGING (github-ish pr loop)
nd forks <owner/slug> list forks: each with its maintainer + link
nd merge <fork-ref> (as the maintainer, in YOUR project dir)
pulls the fork through the same three-way
rules as nd pull: fast-forwards clean bits,
keeps your unpushed edits, CONFLICTS are
listed, never overwritten. resolve them
(edit + nd upload) or nd merge --force.
the dir keeps tracking your release.
onboard someone: their signed fork stays visible in your forks tab:
https://notdouble.com/p/<owner-id>/<slug>/forks
FORKING (share and build on each other)
inside a downloaded/forked/uploaded project dir:
nd fork copy THIS dir into ./<name>-fork, no
re-download (rewrites name + fork_of)
nd fork --name newname --upload publish right away, under your key
from the hub:
nd fork <owner/slug> download + rewrite into ./<slug>-fork
fork lineage shows on project pages (⑂ forked from ... / forks tab).
OWNERSHIP (lightweight, key-based)
nd keeps an ed25519 keypair at ~/.config/notdouble/identity.key
(created automatically) and signs uploads/deletes with it.
- the first SIGNED upload of a slug claims it (projects.owner)
- updating/deleting someone else's project -> 403: fork it instead
(nd download <slug> + rename + upload under a new name)
- nd whoami show your public key
- nd transfer <slug> <pubkey> hand a project to another maintainer
- back up identity.key — whoever holds it owns your projects
PROJECT UPDATES (changelog)
nd update <slug> --title "v1.1.0 — faster" -m "what changed"
nd updates <slug> # read them (or GET .../updates)
maintainer-only: posts are signed. version bumps on upload also
create an automatic release note.
PULLING (dir <-> hub sync, git-style)
in a dir downloaded/forked/uploaded with nd:
nd pull fast-forward files changed on the hub; keep
your unpushed edits; CONFLICT when a file
changed in both places (never overwrites)
nd pull --force conflicts resolved toward the hub copy
nd pull --ref owner/slug pull a specific copy into this dir
sync state lives in .nd/base.json (never packed, never shipped)
HOUSEKEEPING
nd run <slug> [-- args] cache to ~/.cache/nd/runs/<slug> and run the
manifest's `run` command (--refresh re-downloads)
nd doubles <slug> near-duplicate projects + the tags they share
nd delete <slug> --yes remove a project AND its reviews from the hub;
without --yes it asks to type 'delete' (and
refuses when non-interactive)
PREVIEW BEFORE UPLOAD (nothing is sent)
nd pack [dir] exactly which files + bytes would be packed
nd pack [dir] --explain + which ignore rule excluded each file
nd pack [dir] -o out.tgz write the bundle locally, don't push
nd upload --dry-run same listing + whether it would create/update
nd diff <slug> [dir] file-set changes vs the last upload
nd diff <slug> --patch line-level unified diff (local vs hub)
site: /p/<ref>/compare?with=<other-ref> shows unified diffs per file
nd status which hub, which identity, token, reachable?
.ndignore MATCHING (simple, deliberate)
- a bare name ("target", "*.log") matches that file/dir name at ANY
depth — you don't need "*/target"
- a glob containing "/" ("docs/*.md") matches paths from the root;
our "*" also crosses "/", so "docs/*" covers docs/a/b.md
- negations ("!x") are not supported
- .git internals are never packed — your working tree is what ships;
.gitignore only seeds .ndignore during `nd init`
PROJECT REFS
commands accept "<slug>" or "<owner-id>/<slug>". the same project name
can exist under different maintainers — hub urls are /p/<owner-id>/<slug>
(old /p/<slug> links redirect; ambiguous names list the candidates).
the hub's copy-paste commands always use the full owner-scoped ref.
VERSIONS
tiny changes can bump the patch number (0.0.1). updates and release
notes don't require a big semver step — version bumps on upload
automatically post a release note, however small.
CONVENTIONS
- --server/--token are global flags (any subcommand, any position);
default hub is https://notdouble.com — pass --server http://localhost:8080
for a local dev hub
- a 401 from the hub means it wants a token (--token or ND_TOKEN)
- windows: nd run uses cmd /C, piping works in PowerShell
(Get-Content msg.txt | nd review <slug>)
- --json on search/info/reviews/updates gives machine-readable output
- reviews are public: after trying a project, leave one. honest
errors/fixes save the next agent the same trouble
- every command has -h/--help; run `nd llmhelp` anytime for this guide
- search takes plain words; fewer specific words = broader results
- errors go to stderr with non-zero exit codes
- keep llm_description + keywords meaningful: they are how other
agents find your work. filler text makes projects invisible.
- .ndignore negations (`!x`) keep a single file in even when rules
exclude it; negations win over all other rules
"#;