anchorify
Skill version 0.3.0 · Requires anchorify CLI ≥ 0.3.0. Check yours with anchorify --version; upgrade with the procedure in Upgrading below.
Wrap the anchorify CLI to publish or update a file at a stable
public URL on anchorify.io. Supports markdown, code, JSON,
YAML, CSV, TSV, HTML, and slide decks (Marp + reveal.js).
Install or refresh
Preferred — the CLI installs the skill for you:
anchorify skill install
This writes ~/.claude/skills/anchorify/SKILL.md from the
canonical doc, creating directories as needed. Re-run any time to
update; pass --force to overwrite without prompting when the local
file has been modified.
Manual fallback (if you don't yet have the CLI or want to inspect the file before saving):
mkdir -p ~/.claude/skills/anchorify
curl -fsSL https://anchorify.io/docs/anchorify-skill.md \
> ~/.claude/skills/anchorify/SKILL.md
The local copy is a snapshot — re-run anchorify skill install
when the version above (top of this page) is higher than the one in
your local SKILL.md.
Migrating from the old
publish-mdorjustforwardedskill? Move the folder:mv ~/.claude/skills/justforwarded ~/.claude/skills/anchorify(or frompublish-md) and re-fetch from the URL above. The old/docs/publish-md-skill.mdand/docs/justforwarded-skill.mdURLs still 308-redirect to this page, so any existing installation keeps working.
Upgrading the CLI and skill
Trigger: when the user asks any of "upgrade anchorify", "update
the CLI", "is there a newer version", "you're on an old version",
"refresh the skill", "is my skill out of date" — OR when a publish /
lint call fails with error: 4xx mentioning an unsupported field /
content type that newer CLIs handle.
Procedure (run these on the user's behalf, in order):
Read the installed CLI version:
anchorify --versionIf the command isn't found, the CLI isn't installed — skip to step 3.
Read the latest published version:
npm view anchorify-cli versionNo auth required; this hits the public npm registry. The npm package is
anchorify-cli(the bareanchorifyname was already taken by an unrelated utility); the binary it installs is namedanchorify.If installed < latest (or CLI is missing), upgrade and refresh the skill in one go:
npm install -g anchorify-cli@latest && anchorify skill install --force--forceoverwrites the local SKILL.md without prompting — the user is explicitly asking for a refresh, so it's safe.Confirm the new versions:
anchorify --version head -3 ~/.claude/skills/anchorify/SKILL.mdReport the before → after versions to the user. If the upgrade crossed a major version, point them at the release notes / git log for what changed.
Skill-only refresh (the CLI is current but the local SKILL.md is stale): the third command alone is enough:
anchorify skill install --force
The skill version is shown both in this page's title and in the
frontmatter (version: key at the top of the raw markdown). When the
canonical page shows a higher version than the local copy, refresh.
Prerequisites
The user needs the anchorify CLI installed and authenticated.
If anchorify is missing, tell them to install it (one-time setup)
and run anchorify login. The login flow asks for a host
(https://anchorify.io) and a token they copy from
https://anchorify.io/dashboard.
If a publish call returns error: 401, the user is not logged in —
tell them to run anchorify login.
Config & environment
Two env vars change where the CLI reads/writes config and which host it hits. Both exist mainly for sandboxed testing — sub-agents and CI runs should set them to avoid accidentally publishing to production with a developer's logged-in token.
ANCHORIFY_CONFIG_DIR— overrides the config directory (default~/.config/anchorify). Redirects bothauth.jsonandpublished.jsonto the given path. Use this to fully sandbox a test:ANCHORIFY_CONFIG_DIR=/tmp/anchorify-sandbox anchorify login \ --host http://localhost:3737 --token <local-token> ANCHORIFY_CONFIG_DIR=/tmp/anchorify-sandbox anchorify --listNothing in the user's real
~/.config/anchorify/is touched. The legacyJF_CONFIG_DIRis still honored as a fallback so older test scripts keep working.ANCHORIFY_HOST+ANCHORIFY_TOKEN— when both are set, they overrideauth.json(and a one-line[anchorify] using ANCHORIFY_HOST/TOKEN from env (auth.json ignored)notice is printed to stderr ifauth.jsonexists, so the override is visible). Setting only one of them falls back toauth.json— partial env doesn't trigger the override, since mixing an env host with a file token (or vice versa) would produce a confusing token-mismatch. The legacyREPO_SHARE_HOST+REPO_SHARE_TOKENpair is still honored when theANCHORIFY_*pair isn't set.
How URLs work
Per-user URLs are https://anchorify.io/<username>/<slug> —
e.g. https://anchorify.io/alice/q1-report. The username prefix
is fixed per token; the slug is what you pick.
The CLI maintains a local mapping at
~/.config/anchorify/published.json (absolute file path →
{id, url, filename, last_published_at}). You do not have to
remember slugs across sessions — read the mapping or run
anchorify --list.
Publishing a new file (file path NOT in the mapping)
List existing slugs so you don't pick a taken one:
anchorify --listOutput: one tab-separated line per published item —
<url>\t<filename>\t<source-path>. Scope is the signed-in user.Lint the file before publishing so you catch authoring issues (slide-deck frontmatter that won't be detected, JSON parse errors, CSVs with the wrong delimiter, etc.):
anchorify lint <absolute-path>- Exit 0 = clean (or only
info/warn-severity notes). - Exit 1 = at least one
error-severity issue; the file WILL look broken to recipients. Surface the warning to the user and either fix the file or confirm they want to publish anyway.
- Exit 0 = clean (or only
Pick a slug. Rules:
- Lowercase letters, digits, dashes only
- 3–40 chars is the sweet spot (60 max)
- No leading/trailing dash
- Derived from the file's H1 title or filename, NOT generic ("notes", "doc")
- Distinct from every existing slug in
--list
Examples:
q1-report,cardinal-heating-audit,geology-week3.Publish:
anchorify <absolute-path> --slug <slug>Output is a single line — the public URL. Return that URL to the user, nothing else around it. If the publish response carried any authoring warnings, the CLI prints them to stderr; surface those to the user too.
If you get
error: 409 {"error":"slug taken",...}, pick a different slug and retry.
Updating an existing publish
If the file's absolute path is in the local mapping (or the user says "update"), just run with no flags. The CLI looks up the file and updates the same URL:
anchorify <absolute-path>
URL is unchanged; content is replaced. Return the URL.
To update by id explicitly (e.g. "push v2 to hello-world"), pass
--id <id>.
Other operations
Delete a share:
anchorify delete <absolute-path>
# or by slug:
anchorify delete --slug <slug>
The local mapping entry is removed when deleting via path. Deleted URLs return 410 Gone (recipients see the link existed but is gone).
Password-protect a share:
# At publish time:
anchorify <abs-path> --slug <slug> --password <pw>
# Clear an existing password:
anchorify <abs-path> --no-password
Recipients see a password gate; only the correct password renders content. View counts only increment on actual content render.
Visibility (public / unlisted / members):
Every share has one of three tiers. By default a new share is unlisted —
it renders for anyone with the URL, but the page sets noindex so search
engines and AI crawlers don't pick it up. (The pre-V3 value secret is
the legacy alias for unlisted and is still accepted everywhere.) Other
tiers:
public— listed on the owner's profile and indexable.members— only signed-in org admins + project viewers can read; anon →404.
Set the tier at publish time:
# Create as public:
anchorify <abs-path> --slug <slug> --public
# Force unlisted (default; useful as an explicit flip on update):
anchorify <abs-path> --unlisted
# Members-only (signed-in org/project viewers only):
anchorify <abs-path> --members
Updates without a visibility flag preserve the existing tier. The flags are mutually exclusive.
Flip an existing share's visibility without re-publishing:
anchorify visibility <slug-or-id> public
anchorify visibility <slug-or-id> unlisted
anchorify visibility <slug-or-id> members
Resolves <slug-or-id> against --list (matches by id, slug, or URL
suffix). If an unlisted share has a password and you flip it to public,
the server refuses to silently clear the password — re-run with
--force to clear the password and make it public:
anchorify visibility <slug-or-id> public --force
Force a brand-new URL even if the file is in the mapping:
anchorify <abs-path> --new
Content type detection
Anchorify renders shares differently depending on their content
type — markdown via marked, code with highlight.js, CSV/TSV as a
sortable table, JSON/YAML pretty-printed and highlighted, HTML
sanitized and rendered.
The CLI does not classify the file itself. It just sends the filename + content; the server picks a renderer:
- Auto-detection from file extension (default). The server maps
common extensions:
.md,.markdown→ markdown.json→ json.yaml,.yml→ yaml.csv→ csv.tsv→ tsv.html,.htm→ html.js,.ts,.py,.go,.rs,.rb,.sh,.sql, etc. → code (with language inferred for syntax highlighting)- Anything else → markdown
- Explicit
--typeoverride for ambiguous extensions. Pass one of:markdown,code,json,yaml,csv,tsv,html.
# Auto-detect from extension — no flag needed:
anchorify data.csv --slug q1-numbers # renders as a table
anchorify settings.yaml --slug prod-config # yaml-highlighted
anchorify snippet.py --slug pyrun # python-highlighted
# Override when the extension lies (e.g. a .txt file that is actually code):
anchorify weird.txt --slug snippet --type code
anchorify notes.txt --slug brief --type markdown
--type is validated client-side against the allowed set, so you get
an immediate error for typos rather than a server round-trip. Updates
to an existing share that don't pass --type keep whatever type the
share was created with (no silent reclassification).
Fix an existing share's render type without re-publishing:
anchorify type <slug-or-id> markdown
anchorify type <slug-or-id> code
anchorify type <slug-or-id> json
Resolves <slug-or-id> against --list (matches by id, slug, or URL
suffix). Use this to recover from the paste-flow gotcha where leaving
Filename blank in the web "+ New share" form silently classifies the
share as markdown — Python / JSON / CSV pastes will render wrong until
the type is flipped.
Collaboration subcommands
The CLI surfaces five collaboration features. Each prints
tab-separated rows on success so a parent agent or jq-pipe can
parse the output.
notifications — list your in-app notifications
anchorify notifications # all, newest 50
anchorify notifications --unread # unread only
anchorify notifications --limit 10 # cap at 10
Output: <id>\t<kind>\t<created_at_iso>\t<title>\t<link>.
Use this when the user asks "what's new", "any new comments on my
shares", or "did anyone request access". See
/docs/notifications for the full set of
notification kinds.
link-perm — set the anyone-with-the-link permission
anchorify link-perm <slug-or-id> none
anchorify link-perm <slug-or-id> can_view
anchorify link-perm <slug-or-id> can_comment
anchorify link-perm <slug-or-id> can_suggest
Sets the additive grant attached to the URL. none (default) =
read-only. can_comment = anonymous URL-holders can post comments +
reactions. can_suggest = URL-holders can submit suggested changes.
See /docs/link-permissions for the full
matrix.
versions — list and restore a share's version history
# List versions, newest first:
anchorify versions <slug-or-id>
# Output: <version-id>\t<created_at_iso>\t<source>\t<author>\t<status>
# Restore the share to an older version:
anchorify versions restore <slug-or-id> <version-id>
source is one of publish / rollback / suggestion /
agent_edit. status is approved / suggested / rejected. The
restore appends a new rollback row to the history (so even the
rollback is versioned) and prints ok on success.
audit — list audit events for an org
anchorify audit # your home org, 50 events
anchorify audit --org <slug> # explicit org
anchorify audit --limit 200
anchorify audit --action share.delete # filter by action
Output: <created_at_iso>\t<action>\t<actor>\t<target_type>:<target_id>.
The --action filter matches the dotted action keys recorded by the
service — see /docs/audit for the catalog.
suggestions — list suggestions submitted on your shares or by you
# Open suggestions on a specific share you own (owner-only):
anchorify suggestions <slug-or-id>
# Every suggestion YOU have submitted, across every share:
anchorify suggestions mine
The mine form output: <version-id>\t<share-url>\t<status>\t<created_at_iso>.
Approve/reject from the web UI — the CLI lists only.
report-bug — file a bug from the CLI or an agent
# Bare summary — opens with empty body. Anonymous is OK (rate-limited
# per IP); when logged in, the report carries your user id + org.
anchorify report-bug "CLI hung on publish"
# Inline body + agent breadcrumbs.
anchorify report-bug "Editor save 500'd" \
--body "Saving from /editor returned 500; retry succeeded." \
--context '{"slug":"q1-report","last_http_status":500}'
# Body from a file (useful for long repro steps):
anchorify report-bug "Render crash on big csv" \
--file ~/jf-bug-repro.md \
--surface dashboard
Flags:
--body <text>— inline long-form body. Mutually exclusive with--file.--file <path>— read body from a file. Helpful for paste-from-editor.--context '<json>'— free-form JSON breadcrumbs (slug, last HTTP status, recent error message). Must parse to an object.--surface cli|api|agent|dashboard|vscode|raycast|obsidian— which surface filed the report. Defaults tocli.
On success prints the report id on stdout. Every error response from
/api/v1/* also includes a report_with hint with the exact CLI
shape an agent can chain inline.
Notes & failure modes
- File path must be absolute — resolve
~and relative paths first. - The CLI prints only the URL on success. On failure,
error: <code> <body>to stderr. - 401 = run
anchorify login(auth missing or token revoked) - 409 = slug collision; pick a different slug and retry
- 400 = invalid slug format (re-read the slug rules above)
- 404 on
delete= slug doesn't belong to the signed-in user - The returned URL is publicly readable unless a password is set. Warn the user before publishing if the file might contain credentials, client names, or anything they wouldn't want a stranger to see.
- The local mapping at
~/.config/anchorify/published.jsonis plain JSON; read/inspect it directly when debugging.