@infolang/setup-core
v0.4.0
Published
Client-agnostic InfoLang setup: OAuth, session, MCP proxy/gateway, config merge helpers
Readme
@infolang/setup-core
Client-agnostic InfoLang setup primitives shared by @infolang/cursor-setup,
@infolang/claude-setup, and @infolang/mcp-setup.
What it owns
- OAuth PKCE login +
~/.config/infolang/session.json - Local MCP proxy (
:17342) + stdio gateway - Durable gateway install under
~/.config/infolang/gateway/<version>/ - Generic MCP JSON merge helpers (
validateApiKey,buildOAuthMcpConfig, …) - Single
clientId→ hook marker / OAuth?client=/ User-Agent workspace link|sync|watch|status|verify|unlink— local Obsidian vault / folder sync (manifest-diff, privacy-gated dry-run first sync, explicit workspace targeting, retry/backoff, resumable partial-failure state, staged rollout via--limit, post-sync recall spot-check); shared by claude-setup, cursor-setup, and mcp-setup viaworkspace-cli.mjsvault_read/vault_searchMCP tools on the stdio gateway — read-only, path-safe access to the locally linked vault (seemcp-gateway.mjs)
Vault sync modules
| Module | Responsibility |
|---|---|
| lib/vault-parse.mjs | Obsidian markdown/canvas parsing: frontmatter (incl. multi-wikilink fields), wikilinks vs. embeds, Dataview inline fields, heading-aware chunking, JSON Canvas |
| lib/vault-ignore.mjs | Include-glob matching, .gitignore, always-excluded dirs (.obsidian/, .git/), binary detection |
| lib/vault-link.mjs | Linked-vault registry at ~/.config/infolang/sync/<name>.json, path-safe root resolution |
| lib/sync.mjs | Manifest diff (add/modify/delete/rename), chunk-for-push, link/sync/watch/unlink orchestration, privacy disclosure copy |
| lib/vault-transport.mjs | Wire contract for pushing chunks (/v1/execute batch → /v1/remember fallback), retry/backoff with jitter, INFOLANG_API_KEY auth resolution; swappable so contract fixes don't touch sync logic |
| lib/vault-verify.mjs | workspace verify — sample synced chunks, recall them, report hit-rate/score distribution |
| lib/workspace-cli.mjs | Shared workspace <verb> argv parsing + printing, delegated to by all three CLI bins |
| lib/vault-tools.mjs | vault_read / vault_search for the stdio gateway |
Known production contract issue: the managed edge has been observed to
silently ignore RememberRequest.namespace in the request body (writes
land in the caller's default namespace) and to reject a batched
remember op on /v1/execute with 400 unknown op. vault-transport.mjs
works around both — namespace/workspace isolation is done only via the
X-InfoLang-Workspace-Id header, and batch pushes fall back to bounded-
concurrency individual /v1/remember calls when /v1/execute rejects the
op. Live end-to-end push against production has not been re-verified
after this fix; unit tests mock the documented contract
(worktrees/sdk-python/openapi/il-runtime.yaml).
Explicit workspace targeting
X-InfoLang-Workspace-Id is checked against the API key's allowlist —
an unrecognized ID (including any locally-generated one) returns 401.
Sending no header at all routes to the key's own home/default workspace,
which is a valid explicit choice, not a safe implicit default. So
workspace link refuses to proceed without naming exactly one of:
--workspace <uuid>— sendX-InfoLang-Workspace-Id: <uuid>. The UUID must be a real workspace your key is allowlisted for (seeworktrees/connectors/WORKSPACES.mdfor how that's provisioned — a human copies it from the console; there is no self-service way for a key to mint or discover one).--use-key-default— send no workspace header; lands in the key's own default workspace.
There is no third "figure it out" mode. workspace sync, workspace
watch, and workspace verify all re-check the linked target before any
network call and refuse (with a re-link instruction) if a link predates
this requirement.
Auth resolution order
INFOLANG_API_KEY (env var) is checked before session.json,
enabling headless/CI use with no OAuth session on disk at all. If unset,
falls back to the normal OAuth-session / backup-API-key resolution used
elsewhere in this package.
Retry / resume / staged rollout
429and5xx(except501, which signals "/v1/executebatching unsupported, fall back now") get bounded exponential backoff with full jitter, honoringRetry-Afterwhen the server sends one. Any other4xxfails fast with a message naming the file/chunk that was being sent — retrying a malformed request only wastes quota.- Manifest entries are marked synced only after the server has confirmed
them. If a push fails partway through a
workspace syncrun, whatever was actually confirmed is persisted before the error propagates; the rest stays "pending" so the nextworkspace synccall retries only what didn't confirm — nothing already-sent gets resent, nothing unconfirmed gets silently marked done. workspace sync --limit Npushes only the first N pending (added/modified) files, for a staged rollout: link, dry-run,--limit 3,workspace verify, then a full unlimited sync.workspace verify <name> [--samples K]samples K already-synced chunks (default 10, only from files unchanged since their last sync), runs/v1/recallwith each chunk's own text, and reports hit-rate + score distribution — a quick sanity check that a staged push actually landed and is retrievable before syncing the rest of the vault.
Durable gateway
installDurableGateway() copies esbuild bundles from dist/ into a
version-stamped directory. Client MCP configs should reference that path, not
the npx cache.
npm run build # dist/mcp-gateway.bundle.mjs + dist/mcp-proxy.bundle.mjsLocal development
cd packages/setup-core
npm install
npm testPublish
Publish @infolang/overlay first, then this package. Monorepo checkouts keep
file:../overlay; the publish script rewrites it to ^<version> for the npm
tarball only:
# from services repo root
DRY_RUN=1 scripts/publish-npm-packages.sh setup-core # dry-run
scripts/publish-npm-packages.sh overlay setup-core # real publishprepare / npm run build emits dist/ gateway + proxy bundles required at
install time for durable gateway copies.
