{"id":51303868,"url":"https://github.com/phalt/paulias","last_synced_at":"2026-06-30T22:32:20.923Z","repository":{"id":357404264,"uuid":"1236529737","full_name":"phalt/paulias","owner":"phalt","description":"A simple URL shortener that can be deployed to Github pages.","archived":false,"fork":false,"pushed_at":"2026-05-12T16:31:44.000Z","size":109,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T17:37:23.859Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://paulias.dev/","language":"Python","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/phalt.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":null,"support":null,"governance":null,"roadmap":null,"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-05-12T10:31:59.000Z","updated_at":"2026-05-12T16:39:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/phalt/paulias","commit_stats":null,"previous_names":["phalt/paulias"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/phalt/paulias","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phalt%2Fpaulias","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phalt%2Fpaulias/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phalt%2Fpaulias/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phalt%2Fpaulias/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phalt","download_url":"https://codeload.github.com/phalt/paulias/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phalt%2Fpaulias/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34986248,"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-30T02:00:05.919Z","response_time":92,"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":[],"created_at":"2026-06-30T22:32:17.882Z","updated_at":"2026-06-30T22:32:20.874Z","avatar_url":"https://github.com/phalt.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Paulias\n\nA statically hosted URL shortener. Paulias takes a markdown file of short paths and target URLs, generates a directory of HTML redirect files, and pushes them to a GitHub Pages repo. No server, no JavaScript required, no database.\n\n## What is this?\n\nPaulias turns a single human-readable markdown file into a fully working URL shortener hosted for free on GitHub Pages. You manage shortlinks by editing `paulias.md`; Paulias builds and deploys the static HTML.\n\n- **File over app.** The list of shortlinks lives in a single markdown file with YAML frontmatter and link references. Edit it anywhere — GitHub, your phone, Obsidian, or the CLI.\n- **No server.** Each shortlink is a tiny static HTML file containing a meta refresh redirect. GitHub Pages serves it for free.\n- **The config is the source of truth.** The generated HTML is derived; the markdown file is what matters.\n\n## Quick start\n\n```sh\n# install\nuv tool install paulias\n\n# create a new shortener repo\ngh repo create your-username/my-links --public --clone\ncd my-links\n\n# initialise\npaulias init\n\n# add some links\npaulias add gh https://github.com/your-username\npaulias add blog https://yourblog.com\n\n# build and publish\npaulias deploy\n```\n\nYour shortlinks are now live at `https://your-username.github.io/my-links/gh`, etc.\n\n## Installation\n\n```sh\nuv tool install paulias\n```\n\nRequires Python 3.14+. After install, run `paulias` from inside any directory containing a `paulias.md` file.\n\n## Commands\n\n### `paulias init`\n\nWrite a starter `paulias.md` to the current working directory.\n\n```sh\npaulias init\n```\n\nAuto-detects the `repo` field from `git remote get-url origin` if the cwd is a git repo pointing at GitHub. Errors if `paulias.md` already exists unless `--force` is passed.\n\n| Flag | Description |\n|------|-------------|\n| `--force` | Overwrite an existing `paulias.md`. |\n| `--repo` | Set the `repo` field explicitly instead of auto-detecting. |\n\n### `paulias add`\n\nAppend a new shortlink to `paulias.md`.\n\n```sh\npaulias add \u003cpath\u003e \u003curl\u003e\n```\n\nValidates the path and URL before writing. Errors if `\u003cpath\u003e` already exists. Does not build or push.\n\n| Flag | Description |\n|------|-------------|\n| `--force` | Overwrite an existing entry with the same path. |\n| `--deploy` | Run `paulias deploy` immediately after adding. |\n\n### `paulias delete`\n\nRemove a shortlink from `paulias.md`.\n\n```sh\npaulias delete \u003cpath\u003e\n```\n\nErrors if `\u003cpath\u003e` does not exist. Does not build or push.\n\n| Flag | Description |\n|------|-------------|\n| `--deploy` | Run `paulias deploy` immediately after deleting. |\n\n### `paulias list`\n\nPrint the current shortlinks as a formatted table.\n\n```sh\npaulias list\n```\n\nReads only from `paulias.md` — does not look at `docs/`.\n\n| Flag | Description |\n|------|-------------|\n| `--json` | Print as JSON instead of a table. |\n\n### `paulias open`\n\nOpen a shortlink's target URL in the default browser.\n\n```sh\npaulias open \u003cpath\u003e\n```\n\nLooks up `\u003cpath\u003e` in `paulias.md` and opens its target URL directly — useful for quick verification without typing the full domain.\n\n| Flag | Description |\n|------|-------------|\n| `--print` | Print the target URL to stdout instead of opening it. |\n\n### `paulias deploy`\n\nBuild the site and push to GitHub Pages.\n\n```sh\npaulias deploy\n```\n\nIn order: validate `paulias.md` → wipe and regenerate `docs/` → stage files → commit → push. The commit message is generated automatically: `Deploy N shortlinks (M added, K removed)`.\n\n`deploy` is idempotent — running it twice with no changes produces no commit.\n\n| Flag | Description |\n|------|-------------|\n| `--dry-run` | Build to `docs/` but do not commit or push. |\n| `--no-push` | Commit but do not push. |\n| `--message`, `-m` | Override the generated commit message. |\n| `--force` | Skip the validation step (not recommended). |\n\n## `paulias.md` format\n\nThe config lives at `paulias.md` in the root of your shortener repo.\n\n```markdown\n---\ncname: paulias.dev\nrepo: your-username/my-links\nbranch: main\ntitle: \"My shortlinks\"\nabout: \"A personal collection of short links.\"\nfooter: \"Made by [You](https://yoursite.com) with [Paulias](https://github.com/phalt/paulias).\"\n---\n\n[gh]: https://github.com/your-username\n[blog]: https://yourblog.com\n```\n\nShortlinks are standard markdown link reference definitions. Each line maps a short path to its target URL. The order of entries is preserved on disk so the file diffs cleanly.\n\n### Frontmatter fields\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `repo` | yes | GitHub repo in `owner/name` form. Used by `deploy`. |\n| `cname` | no | Custom domain. Writes a `CNAME` file to `docs/CNAME`. |\n| `branch` | no | Branch to push to. Default `main`. |\n| `title` | no | Title shown on the index page. Default `Paulias`. |\n| `about` | no | Short description shown on the index page. |\n| `footer` | no | Footer text. Supports inline markdown for links and emphasis. |\n\n### Path rules\n\n- Lowercase alphanumerics, hyphens, and underscores only.\n- Must start with an alphanumeric character.\n- Maximum 64 characters.\n- Must not collide with reserved paths: `cname`, `404`, `index`, `style`, `docs`, `assets`, `static`, `templates`, `paulias`.\n\n## Custom domain setup\n\nSet `cname` in your frontmatter to your custom domain:\n\n```yaml\ncname: links.yourdomain.com\n```\n\n`paulias deploy` will write a `CNAME` file to `docs/CNAME`. Then in your DNS provider, add a `CNAME` record pointing `links.yourdomain.com` to `your-username.github.io`.\n\nFinally, in your GitHub repo settings under **Pages**, set the custom domain.\n\n## Deployment workflow\n\n```sh\n# initialise once\npaulias init\n\n# daily usage\npaulias add gh https://github.com/your-username\npaulias add f1 https://www.formula1.com\npaulias deploy\n\n# editing by hand also works\nvim paulias.md\npaulias deploy\n```\n\n`paulias add` and `paulias delete` only edit `paulias.md`. Use `paulias deploy` to build and ship. This separation lets you batch edits, edit the config by hand, and review the diff before publishing.\n\n## Template customisation\n\nCreate a `templates/` directory next to `paulias.md` to override any bundled template:\n\n```\nmy-links/\n├── paulias.md\n└── templates/\n    ├── base.html.j2\n    ├── index.html.j2\n    └── 404.html.j2\n```\n\nLocal templates take precedence over the bundled defaults. Available Jinja2 context variables:\n\n| Variable | Type | Description |\n|----------|------|-------------|\n| `title` | str | Site title from frontmatter. |\n| `about` | str | About text from frontmatter. |\n| `footer` | str | Footer HTML, already rendered from markdown. |\n| `cname` | str | Custom domain or empty string. |\n| `shortlinks` | list | List of `{\"short\": ..., \"target\": ...}`. |\n\n## Development\n\n```sh\ngit clone https://github.com/phalt/paulias\ncd paulias\nmake install   # uv sync\nmake test      # pytest\nmake lint      # ruff check\nmake format    # ruff format\n```\n\n## Fork your own copy\n\nPaulias is designed to be self-hosted on GitHub Pages with zero running costs. To set up your own shortener:\n\n1. Create a new public GitHub repo (e.g. `your-username/my-links`).\n2. In repo **Settings → Pages**, set source to the `main` branch, folder `/docs`.\n3. Install Paulias: `uv tool install paulias`.\n4. Clone your repo, run `paulias init`, add links, and `paulias deploy`.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphalt%2Fpaulias","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphalt%2Fpaulias","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphalt%2Fpaulias/lists"}