Columbia Pages is a small self-hosted service for publishing clean HTML reports
and getting back a shareable URL. It includes a Go server, SQLite storage, the
cpages CLI, a built-in report theme, and an agent skill.
agent -> cpages CLI -> authenticated API -> SQLite
|
browser <- public unguessable URL <---+
Published pages are public to anyone who has their URL. Columbia Pages is best for reports you intend to share, not for storing secrets.
Giving this repository URL to an agent? Start with Agent Setup. It has separate, end-to-end checklists for connecting a new device to an existing instance and deploying a new Railway instance from scratch.
Install with the latest patch release of Go 1.25 or newer:
go install github.com/davis7dotsh/columbia-pages/cmd/cpages@latestMake sure $(go env GOPATH)/bin is on PATH, then confirm the install:
cpages versionIf someone has already deployed Columbia Pages, ask for its public HTTPS URL, then run:
cpages login --server https://your-service.up.railway.app
cpages statuslogin prints an activation URL and short code. Open the URL, sign in with the
deployment's admin passcode, review the requested scopes, and approve the
device. The CLI receives a revocable 90-day token and saves it in
~/.config/columbia-pages/config.json with mode 0600. A successful status
check identifies the token, scopes, label, and expiry. Run login again to switch
instances or replace a token.
Create a Railway project from this repository, attach a volume at /data, and
give the same service two domains: one for public content and one for the
control plane. Set:
COLUMBIA_PAGES_ADMIN_PASSCODE=<a long random owner secret>
PUBLIC_BASE_URL=https://pages.example.com
CONTROL_BASE_URL=https://your-service.up.railway.app
Railway supplies PORT; the container stores SQLite at
/data/columbia-pages.db and exposes /healthz. Published HTML is active, so
the two origins are a security requirement even though both route to the same
container.
After Railway reports the deployment healthy, connect exactly as you would to an existing instance:
cpages login --server https://your-service.up.railway.app
cpages statusSee the complete Railway guide for agent-friendly deployment steps, backups, custom domains, upgrades, and production notes.
cpages create --title "First report" - <<'HTML'
<header>
<h1>First report</h1>
<p class="dek">A small report published from the command line.</p>
</header>
<section>
<h2>Summary</h2>
<p>Columbia Pages is ready.</p>
</section>
HTMLThe command prints the public URL. Body-only HTML receives the house theme automatically.
The source skill is .skills/columbia-pages. From a
clone, link it into the skill directory used by your agent:
git clone https://github.com/davis7dotsh/columbia-pages.git
cd columbia-pages
mkdir -p ~/.agents/skills
ln -s "$(pwd)/.skills/columbia-pages" ~/.agents/skills/columbia-pagesFor a product-specific location, replace ~/.agents/skills in both commands
with ~/.codex/skills or ~/.claude/skills. The committed
.claude/skills/columbia-pages symlink also makes the skill available to Claude
Code while working in this repository.
The skill treats the theme as a flexible component vocabulary. Semantic HTML works without a fixed report template.
cmd/serverruns the HTTP service.cmd/cpagesmanages login and pages.internal/storepersists page HTML and metadata in one SQLite database.internal/webserves the authenticated API and public page URLs.theme/theme.cssis embedded into the server binary..skills/columbia-pagesteaches agents how to publish accessible reports.
Themed pages store body HTML and are wrapped by the server. Raw pages store and serve a complete document verbatim.
cpages login [--server URL] [--device-name NAME] [--read-only]
cpages logout
cpages status
cpages create --title "Title" [--slug s] [--raw] [--ttl N] <file|->
cpages list [--limit N] [--json]
cpages get [--json] <id>
cpages update [--title T] [--slug s] [--raw] [--ttl N] <id> [<file|->]
cpages delete <id>
Put flags before positional arguments. Use - to read page HTML from stdin.
- The management API accepts scoped, revocable device tokens on the control origin.
- Public page IDs contain roughly 71 bits of randomness.
- Page HTML is trusted publisher content and is not sanitized.
- Raw pages may execute JavaScript.
- CLI credentials are stored in
~/.config/columbia-pages/config.jsonwith mode0600.
Read SECURITY.md before exposing an instance publicly. Browser authentication never shares an origin with published page HTML. The protocol and token lifecycle are documented in docs/device-authorization.md.
go test ./...
go vet ./...
gofmt -w .Run the local service with an isolated database and config directory. Plain HTTP is accepted only for loopback development:
Terminal 1:
export COLUMBIA_PAGES_ADMIN_PASSCODE=dev-admin-secret
export PUBLIC_BASE_URL=http://pages.localhost:8080
export CONTROL_BASE_URL=http://control.localhost:8080
export DB_PATH=/tmp/columbia-pages.db
go run ./cmd/serverIn another terminal:
export COLUMBIA_PAGES_CONFIG_DIR=/tmp/columbia-pages-config
cpages login --server http://pages.localhost:8080See CONTRIBUTING.md and AGENTS.md for repository guidance.
Columbia Pages is available under the MIT License.