planhost
v0.1.1
Published
Static HTML draft publishing for agents.
Readme
Planhost
Planhost is a strict TypeScript service and CLI for publishing static HTML drafts from agents.
Requirements
- Node.js 20 or newer.
- npm.
Setup
npm ci
npm run buildStart a local service:
PLANHOST_BOOTSTRAP_API_KEY=<bootstrap-api-key> npm run devUse a private value generated by your secret manager for PLANHOST_BOOTSTRAP_API_KEY. It must be a Planhost API key token value; do not commit or paste real keys into docs, fixtures, shell history, or uploaded HTML.
The service starts on http://127.0.0.1:3000 by default, initializes the SQLite schema idempotently, ensures the HTML storage root exists, and inserts or refreshes the bootstrap API key when provided.
Service Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| PLANHOST_HOST | 127.0.0.1 | HTTP listen host. |
| PORT | 3000 | HTTP listen port. Must be between 1 and 65535. |
| PLANHOST_PUBLIC_BASE_URL | request base URL | Canonical public URL used in API responses. Supports wildcard form such as https://*.planhost.example. |
| PLANHOST_BOOTSTRAP_API_KEY | none | Optional bootstrap API key inserted or refreshed as key_bootstrap for acct_bootstrap. Required for first-use deployments unless the database is already seeded. |
| PLANHOST_DATABASE_PATH | ./data/planhost.sqlite | SQLite database path. Relative paths resolve from the current working directory. |
| PLANHOST_HTML_DIR | ./data/html | Filesystem root for stored HTML objects. Relative paths resolve from the current working directory. |
| PLANHOST_MAX_HTML_BYTES | 524288 | Maximum uploaded HTML size in UTF-8 bytes. |
| PLANHOST_UPLOAD_BODY_LIMIT | 2mb | Express JSON body limit for upload/API requests. |
| PLANHOST_UPLOAD_IP_RATE_LIMIT_WINDOW_MS | 60000 | Upload rate-limit window per source IP. |
| PLANHOST_UPLOAD_IP_RATE_LIMIT_MAX | 60 | Maximum upload requests per source IP window. |
| PLANHOST_UPLOAD_RATE_LIMIT_WINDOW_MS | 60000 | Upload rate-limit window per authenticated API key. |
| PLANHOST_UPLOAD_RATE_LIMIT_MAX | 30 | Maximum upload requests per authenticated API key window. |
| PLANHOST_REDACTION_VALUES | empty | Comma-separated private values to redact from errors and reject from uploaded HTML/metadata. |
CLI
The package binary is planhost. In this repository, build first and run the local binary with node dist/bin/planhost.js.
Configure credentials:
planhost auth set <api-key> --api-url http://localhost:3000Local repository equivalent:
npm run build
node dist/bin/planhost.js auth set <api-key> --api-url http://localhost:3000Check identity:
planhost whoamiUpload a new draft or update a known local file mapping:
planhost upload ./plan.html
planhost upload ./plan.html --draft <draft-id>
planhost upload ./plan.html --newList and delete owned drafts:
planhost drafts list
planhost drafts delete <draft-id>The CLI stores state in ~/.planhost with 0600 JSON files. The state directory is created with 0700 permissions. API keys are never printed after auth set.
CLI Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| PLANHOST_API_URL | stored config, then http://localhost:3000 | API base URL for whoami, upload, drafts list, and drafts delete. A command --api-url option takes precedence when available. |
| PLANHOST_API_KEY | stored credentials | API key used for authenticated CLI requests. Takes precedence over ~/.planhost/credentials.json. |
| PLANHOST_HOME | ~/.planhost | CLI state directory override. Mainly for tests and isolated local runs. |
| PLANHOST_REDACTION_VALUES | empty | Comma-separated private values to redact from CLI errors and reject during local upload validation. |
Configuration precedence is command --api-url, PLANHOST_API_URL, stored config, then http://localhost:3000. API key precedence is PLANHOST_API_KEY, then stored credentials.
Tests
npm run typecheck
npm run test:unit
npm run test:acceptance
npm run smoke
npm run buildnpm run test runs unit and acceptance tests. npm run smoke builds the package and runs the executable smoke tests under test/smoke.
The acceptance suite covers draft lifecycle, public rendering, API key lifecycle, and redaction. Redaction tests use configured sentinel values and generated in-memory tokens; real secrets must not appear in fixtures, docs, logs, CLI output, public draft views, or generated artifacts.
Static HTML Policy
Planhost accepts one complete static HTML document per upload.
Allowed:
- Semantic HTML.
- Inline CSS or a
<style>block. - Standard metadata such as charset, viewport, and title.
- HTTPS links and HTTPS or data URL images when needed.
Rejected:
- JavaScript and
<script>tags. - Inline event handlers such as
onclick,onload, oronerror. javascript:,vbscript:, orfile:URLs.- Forms.
- Iframes, embeds, objects, applets, base tags, external stylesheet links, and
srcdoc. - Meta refresh redirects.
- Unsafe inline CSS such as
expression(,behavior:, orurl(javascript:). - Planhost API-key-like tokens and configured redaction values.
Agent Skill
The bundled agent skill lives at skills/planhost/SKILL.md. It instructs agents to produce safe static HTML, upload with npx planhost upload <file path>, and return the public Planhost URL.
