{"id":50967045,"url":"https://github.com/domuk-k/pubifact","last_synced_at":"2026-06-18T21:30:58.768Z","repository":{"id":364202882,"uuid":"1266855182","full_name":"domuk-k/pubifact","owner":"domuk-k","description":"Agent-native, self-hostable artifact hosting — publish HTML/Markdown to a shareable URL on your own Cloudflare Worker","archived":false,"fork":false,"pushed_at":"2026-06-12T04:25:44.000Z","size":92,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T05:10:31.080Z","etag":null,"topics":["agent-skills","claude-code","cloudflare-workers","markdown","r2","self-hosted"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/domuk-k.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T02:33:54.000Z","updated_at":"2026-06-12T04:25:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/domuk-k/pubifact","commit_stats":null,"previous_names":["domuk-k/pubifact"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/domuk-k/pubifact","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domuk-k%2Fpubifact","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domuk-k%2Fpubifact/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domuk-k%2Fpubifact/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domuk-k%2Fpubifact/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/domuk-k","download_url":"https://codeload.github.com/domuk-k/pubifact/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/domuk-k%2Fpubifact/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34508860,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-skills","claude-code","cloudflare-workers","markdown","r2","self-hosted"],"created_at":"2026-06-18T21:30:57.874Z","updated_at":"2026-06-18T21:30:58.760Z","avatar_url":"https://github.com/domuk-k.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pubifact\n\n[![CI](https://github.com/domuk-k/pubifact/actions/workflows/ci.yml/badge.svg)](https://github.com/domuk-k/pubifact/actions/workflows/ci.yml)\n[![MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nTurn a static HTML or Markdown file into a shareable URL with one command — for\nany AI coding agent (Claude Code, OpenCode, Codex, …). Markdown is rendered to\na clean HTML page.\n\n```\n\"publish foo.html\"             →  https://pubifact.\u003cyou\u003e.workers.dev/x7qk2abc.html\n\"publish notes.md\"             →  rendered to HTML at the same kind of URL\n\"publish secret.md --password\" →  same, but viewers must enter the password\n```\n\nTwo pieces:\n\n| Piece | What | Where |\n|-------|------|-------|\n| **skill** | The thin client an agent runs (`publish.sh` + `SKILL.md`). Reads config, prompts you to run `init.sh` if none is set. | [`skills/pubifact/`](skills/pubifact/) |\n| **worker** | A free `POST file → URL` service: Cloudflare Worker + R2, renders Markdown. | [`worker/`](worker/) |\n\nSee [`DESIGN.md`](DESIGN.md) for the why.\n\n## Use the skill\n\nInstall it for your agent (Claude Code example — personal skills apply to every\nproject):\n\n```bash\nnpx skills add domuk-k/pubifact\n```\n\nThen ask your agent to \"publish this\" or \"share this page\". That's it.\n\n**How the first publish works — init-first.** On the first publish the skill\ndetects that no instance is configured and offers to set up your own free\npermanent instance (~2 minutes). No content is uploaded to any third-party host\n— your data only ever reaches your own infrastructure.\n\nAlternatively, install by hand with a symlink:\n\n```bash\nln -s \"$PWD/skills/pubifact\" ~/.claude/skills/pubifact\n```\n\n## Set up your own backend (free, permanent)\n\nOne-time, ~3 minutes. Needs a free Cloudflare account. The skill's `init.sh`\nwalks you through it:\n\n```bash\nbash ~/.claude/skills/pubifact/init.sh setup\n```\n\nOr click the button below (no CLI needed):\n\n[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/domuk-k/pubifact/tree/main/worker)\n\n\u003c!-- TODO: verify button resolves worker/ subdir + R2 auto-provision after repo is public --\u003e\n\nAfter either path, add your endpoint and token to the config file:\n\n```json\n{\n  \"endpoint\": \"https://pubifact.\u003caccount\u003e.workers.dev\",\n  \"token\": \"\u003cyour-upload-token\u003e\"\n}\n```\n\nDefault location: `~/.config/pubifact/config.json` (written automatically by\n`init.sh`; the `token` key is only needed if you set `UPLOAD_TOKEN` on the\nworker).\n\nEnvironment variables override the config file (advanced / CI use):\n\n```bash\nexport PUBIFACT_ENDPOINT=https://pubifact.\u003caccount\u003e.workers.dev\nexport PUBIFACT_TOKEN=\u003cyour-upload-token\u003e\n```\n\n## What init.sh does, step by step\n\nIf you prefer to do it by hand:\n\n```bash\ncd worker\nnpm install\nnpx wrangler login                         # opens browser, authorize\nnpx wrangler r2 bucket create pubifact     # create the storage bucket\nnpx wrangler deploy                        # deploy the Worker — prints your URL\n```\n\nRecommended hardening:\n\n```bash\nnpx wrangler secret put UPLOAD_TOKEN       # require a bearer token on uploads\n```\n\nThen write `~/.config/pubifact/config.json` with your endpoint and token.\n\n### Cost\n\nCloudflare free tier covers small usage at ~$0: Workers 100k requests/day, R2\n10 GB storage and **zero egress fees** (ideal for serving HTML).\n\n## Worker API\n\n| Method \u0026 path | Purpose |\n|---------------|---------|\n| `POST /up` | Publish. Body: multipart `file` (preferred) or raw bytes. Returns two text lines — the URL, then a one-time **delete token** — or JSON (`url`, `deleteToken`) if `Accept: application/json`. |\n| `GET /:key` | Serve the page as `text/html`. 404 if unknown. |\n| `HEAD /:key` | Headers only (for link unfurlers). |\n| `DELETE /:key` | Take the page down. `Authorization: Bearer \u003cdelete-token\u003e` (or the operator's `UPLOAD_TOKEN` as master key). |\n\n`POST /up` fields / params:\n\n- `file` — the artifact. `.md`/`.markdown` filenames are rendered to HTML;\n  for a raw body use `?type=md` and optionally `?name=foo.md`.\n- `password` — optional. If set, the page requires it to view (HTTP Basic, any\n  username; or `?k=\u003cpassword\u003e`). Protected pages send `Cache-Control: private`.\n- Size cap: 5 MB. If `UPLOAD_TOKEN` is configured, send `Authorization: Bearer \u003ctoken\u003e`.\n\n```bash\ncurl -F file=@page.html https://\u003cyour\u003e.workers.dev/up\ncurl -F file=@notes.md -F password=hunter2 https://\u003cyour\u003e.workers.dev/up\n\n# take it down later (token = line 2 of the publish response)\ncurl -X DELETE -H \"Authorization: Bearer \u003cdelete-token\u003e\" https://\u003cyour\u003e.workers.dev/x7qk2abc.html\n# or from the skill:\nbash skills/pubifact/publish.sh --down \u003curl\u003e --token \u003cdelete-token\u003e\n```\n\nThe delete token is shown **once**, at publish time. A page published before\nthis feature existed can only be removed with the operator's `UPLOAD_TOKEN`.\n\n## Caveats\n\n- Pages are hosted on a **public host**; without `--password` anyone with the\n  link can open it and its JS runs. Use `--password` for private content.\n- `--password` gates *reading* (good for \"share with specific people\"). It is\n  **not** a fit for NDA/regulated data: content still lives in your R2, and the\n  gate is only as strong as the password. Keep contractually-restricted material\n  in sanctioned infra.\n- An open upload endpoint can be abused; flip on `UPLOAD_TOKEN`, the 5 MB cap,\n  or Cloudflare rate-limiting if needed.\n- Artifacts must be self-contained — inline assets, no relative file refs.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for the trust model and how to report\nvulnerabilities.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdomuk-k%2Fpubifact","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdomuk-k%2Fpubifact","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdomuk-k%2Fpubifact/lists"}