npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jfrk/pony

v0.6.2

Published

Git-backed agent-native project workspace.

Readme

Pony: Git-Backed Agent-Native Project Workspace

Status: early release. The CLI, repository state, server-backed web view, and static snapshots are available in @jfrk/pony.

Short Version

Pony is a repository-native project workspace for AI-assisted projects.

It stores project state as files in the git repository, exposes a simple browser UI for customers and project managers, and lets AI agents mutate state through a CLI first. MCP is planned as a thin adapter over the same core logic, not as a separate source of behavior.

The v1 product is deliberately narrow:

  • a read-only project web view,
  • a visible global inbox for all human input,
  • a kanban board rendered from repo files,
  • a minimal customer-facing documentation area,
  • a CLI for agents and maintainers,
  • a packaged server app for viewing project state and receiving inbox messages,
  • a static read-only snapshot for ordinary web servers.

The key idea is that customers and project managers should not need to know where feedback belongs. They write into a shared inbox. AI agents then triage that input according to project rules, link it to tasks/docs, create new tasks when appropriate, and update the board.

Get Started

Pony requires Node.js 22 or newer. Activate the Node.js version you use, install the launcher, verify it, then add Pony to the ChatGPT desktop app's supported personal plugin marketplace:

nvm use 22
npm install --global @jfrk/pony
pony --version
pony setup chatgpt

With nvm, global npm packages belong to the active Node.js installation. After installing or switching to another Node.js version, install the Pony launcher for that version as well. Use node --version, npm prefix --global, and command -v pony to verify which installation a terminal resolves. The first line from pony --version should start with Pony launcher.

pony setup chatgpt is safe to rerun. It creates or updates Pony's entry in ~/.agents/plugins/marketplace.json without replacing other personal plugins. Restart ChatGPT, open Plugins > Personal, install Pony, and start a new task so ChatGPT discovers the skill.

The separate Codex CLI remains an optional advanced surface. Users who have it installed can instead run pony setup codex to add the public JFRK plugin catalog and install Pony from the terminal.

Claude Code 2.0.12 or newer is supported through its official plugin CLI:

pony setup claude

This adds Pony's public npm-backed marketplace and installs pony@jfrk-pony at Claude Code's user scope, making the skill available across projects without changing project settings. Rerunning the command refreshes the marketplace, keeps a matching installation unchanged, and upgrades an older plugin to the running Pony version. A newer installed plugin is left untouched. Run /reload-plugins in Claude Code or start a new session after setup. This command targets Claude Code only, not Claude Desktop.

Initialize each repository that should use Pony:

cd /path/to/project
pony init --name "Project name" --language sv
pony doctor
pony start

Initialization creates version-controlled project state in .pony/ and pins a compatible local Pony runtime as a development dependency. In repositories without package.json, Pony creates a minimal private manifest and adds node_modules/ to .gitignore. PHP, Python, and other non-JavaScript projects therefore get reproducible Pony tooling without becoming JavaScript applications.

To update the launcher and a project's runtime later:

pony upgrade

pony upgrade resolves npm's stable latest version once, upgrades the global launcher first, and then uses the repository's detected npm, pnpm, Yarn, or Bun installation to upgrade the local runtime to that same version. Use --launcher-only or --project-only when only one installation should change; the flags are mutually exclusive. A project-only upgrade is rejected when it would become incompatible with the current launcher.

If the launcher succeeds but the project update fails, Pony keeps the launcher upgrade, exits non-zero, and prints the exact local package-manager command to retry. With nvm, global packages belong to the active Node.js version; reactivate the intended version and retry the printed npm command if the global step fails.

Interactive Pony commands perform a silent best-effort npm update check at most once every 24 hours after success, or once per hour after a failed or timed-out lookup. The request starts before command delegation and has a short timeout, so normal command execution does not wait for the registry. Checks are disabled in CI, for non-TTY and --json output, while pony upgrade runs, and when PONY_DISABLE_UPDATE_CHECK=1 is set. Cache state lives in the current user's platform cache directory, never in the repository.

Plugin integrations have separate lifecycles. Package upgrades do not modify ChatGPT, Codex, or Claude Code plugin state; rerun the corresponding pony setup command when an installed integration should be synchronized.

The global pony owns setup and project discovery. Project commands such as doctor, task, and start are always provided by the repository's local package. npm exec -- pony remains available when a user wants to invoke the local installation directly.

Releasing

Releases use npm Trusted Publishing from the private jfrk/pony repository. The GitHub Actions workflow uses short-lived OIDC credentials to publish tagged releases directly; it does not store an npm publishing token or make the private repository readable. npm provenance is unavailable because the source repository is private.

Configure the package once under npm > @jfrk/pony > Settings > Trusted Publisher:

  • provider: GitHub Actions,
  • organization: jfrk,
  • repository: pony,
  • workflow filename: publish.yml,
  • environment: leave empty,
  • allowed actions: npm publish only.

After the first successful OIDC release, set npm publishing access to Require two-factor authentication and disallow tokens and revoke obsolete automation tokens.

For each release, update package.json, package-lock.json, .codex-plugin/plugin.json, .claude-plugin/plugin.json, .claude-plugin/marketplace.json, and CHANGELOG.md, commit the release, then push a tag matching the package version, such as v0.2.0. The workflow validates the tag, formatting, tests, types, build, and isolated package smoke test before running npm publish. Contributors can run the same artifact check after npm run build with npm run test:package. The matching Git tag is the release approval; there is no separate npm review step.

Why Pony Instead of GitHub Issues and Projects

GitHub Issues and Projects coordinate people around GitHub objects. Pony coordinates people and AI agents around a repository. Its core difference is where project state lives and how responsibility is divided between humans and agents.

  • The project plan travels with the code. Tasks, feedback, and documentation live in .pony/, so they share the repository's history, review model, portability, and backup story. A project handover can include both the implementation and the context needed to understand it.
  • Pony is agent-native rather than tied to one agent platform. Agents work through a local CLI and a documented file contract. They can inspect context, validate records, triage feedback, and update project state without depending on GitHub-specific APIs or a particular AI provider.
  • Humans describe needs instead of administering tickets. Customers and project managers write to one inbox instead of choosing the right repository, issue type, label, project, status, or template. Agents preserve the original message and turn it into structured, actionable work.
  • Non-technical stakeholders get a focused project surface. The browser UI shows the board, inbox, and shared documentation without exposing branches, pull requests, labels, or other developer-oriented controls.
  • Feedback, work, and decisions stay connected. Inbox messages, tasks, and documents can reference each other, leaving a trace from the original request to the resulting work and the decisions behind it.
  • The workflow remains plain Git. Pony can be used with different Git hosts, self-hosted infrastructure, or local repositories. Project rules and workflow configuration can be versioned and reviewed alongside the project.

Pony is a strong fit for small AI-assisted development teams, customer projects, consultancies, self-hosted environments, and projects that need a complete and portable handover. It deliberately does not compete with GitHub Projects on feature breadth. GitHub remains the stronger choice when a team needs mature real-time collaboration, advanced permissions, notifications, organization-wide reporting, roadmaps, or a large integration ecosystem.

Pony is an agent-native project workspace that lives in the Git repository. Customers get a simple project view and inbox, while agents handle triage, structure, and project updates. The result is less administration, stronger traceability, and project context that can move with the code.

Dogfooding This Repository

This repository now uses Pony to track Pony's own project work.

The boundary is intentional:

  • src/, tests/, package files, and Astro config are the implementation of Pony as a product.
  • .pony/ is dogfooded project state for this repository. It is not a fixture, template, cache, or generated build output.
  • .pony/ should be committed like normal project data when its contents are meaningful.
  • dist/, .astro/, .pony-web/, and node_modules/ are runtime/build artifacts and should stay untracked.

Set Up The Dogfood Launcher

The package checkout is its own project runtime. Node package self-reference lets the launcher discover this root without a circular dependency or a second link inside node_modules/. Prepare a clean checkout with the active nvm installation:

nvm use
npm install
npm run build:cli
npm link
pony --version
pony doctor
pony context

pony --version should report compatible launcher and project-runtime versions. The global link belongs to the active Node.js version, so rerun npm link after switching nvm versions. Rebuild with npm run build:cli after changing CLI or core source; the global link continues to point at this checkout, but it runs the compiled files in dist/.

If Pony finds the checkout but reports a missing CLI runtime, run npm run build:cli. If command -v pony or pony --version still resolves another installation, check npm prefix --global after nvm use, then rerun npm link. Do not run npm link @jfrk/pony in this repository: package self-reference already provides the project-runtime link. Consumer repositories continue to use the local dependency installed by pony init.

When changing project-management state for Pony itself, prefer the Pony CLI:

pony inbox add "Message body" --author "Name" --email "[email protected]"
pony inbox add "Message with files" --email "[email protected]" --attachment ./brief.pdf
pony task create "Task title" "Task body" --status triage
pony task update TASK-001 "Rewritten body" --title "Revised title"
pony task move TASK-001 in_progress
pony task prioritize TASK-001 soon
pony task rename-status todo backlog
pony task migrate-priorities --inspect
pony task renumber TASK-001 TASK-010
pony task shift TASK-010 --by 2
pony docs create "Doc title" "Doc body" --type note
pony docs update DOC-001 "Rewritten body"
pony inbox link MSG-... --task TASK-001 --doc DOC-001
pony task link TASK-001 --inbox MSG-... --doc DOC-001

Manual edits inside .pony/ are acceptable for repairs or deliberate bulk changes, but normal workflow changes should go through Pony commands so the dogfooding path exercises the same file contract as external projects.

Do not add special product behavior that only works because this repository contains .pony/. Pony's implementation must continue to treat .pony/ as ordinary project data supplied by whatever repository is being viewed or mutated.

Background

The original need was a way to keep a kanban board inside a git repo as files, instead of using GitHub Projects or another SaaS project-management surface. The board should be manageable by AI agents, auditable through git, and usable without forcing less technical users into terminals or GitHub workflows.

During discovery, a few existing tools shaped the direction:

  • tiki is attractive because it is broader than a kanban board: it treats tasks, docs, prompts, and notes as a Markdown workspace in a git repo. Its drawback for this use case is that it is terminal-first.
  • VibeOps Tracker is close to the desired v1: web board, Markdown issue files, MCP tools, and agent workflow. It is primarily local-first and localhost-only.
  • Knutpunkt is also close: Markdown task files, web UI, backend API, and MCP server. It is narrower and more kanban-shaped.
  • LiveBoard shows a useful Markdown-native kanban UI/CLI/API direction, though the AI agent layer appears to be roadmap rather than core.
  • kanban-md is useful as an agent-first reference: per-task Markdown files, claims, CLI/TUI, compact output, and skills. It is still terminal/TUI oriented rather than a customer-friendly browser surface.
  • Task Master AI is relevant for agent task workflow patterns, but it is not primarily a browser kanban/document workspace.

The conclusion was not to clone any one of these. Pony should borrow the repo-file contract and agent workflow ideas, but provide a browser-first read-only surface for non-technical stakeholders.

Product Principles

Files Are the Contract

The canonical project state lives in .pony/ inside the repository. The app, CLI, server, and future MCP adapter all read and write the same files through a shared core library.

Generated indexes and caches may exist later, but they are not the source of truth.

Pure Git, Not GitHub Product Features

It is acceptable to commit and push files to a git remote. It is not acceptable for the core product model to depend on GitHub Issues, Discussions, Projects, the GitHub CLI, or similar product-specific features.

GitHub may host a repository, but Pony's workflow should remain plain git.

Humans Write to an Inbox

Customers and project managers often do not know which card, document, or workflow state a comment belongs to. Asking them to place feedback correctly creates friction and often produces bad structure.

In v1, all human input goes into a global inbox. It is visible to everyone in the project view. Agents later triage, link, summarize, create tasks, or close items based on project guidelines.

Agent Mutation, Human Visibility

The web UI is mostly read-only in v1. Humans can submit inbox messages in server-backed mode, but board/task/doc mutation is expected to happen through the CLI and AI agents.

Keep v1 Small

The product should avoid building a full collaborative project-management app in v1. It should prove the core loop:

  1. Project state lives in git-backed files.
  2. Humans can see the project in a browser.
  3. Humans can submit visible input.
  4. Agents can triage and mutate the state safely through CLI commands.

Target Users

Primary users:

  • developers and AI agents working inside a repo,
  • project leads who want git-backed project state,
  • customers and project managers who need a browser view but should not need to understand git, Markdown, or agent workflows.

V1 Scope

V1 includes:

  • package-installed CLI,
  • .pony/ repository state folder,
  • Markdown files with YAML frontmatter,
  • mostly read-only web UI with inbox submission in server mode,
  • kanban board,
  • shared visible inbox,
  • minimal documentation list,
  • server-backed inbox submit flow,
  • configurable git write policy,
  • context export for agents.

V1 does not include:

  • user accounts inside Pony,
  • full task editing in the browser,
  • comments attached directly to cards,
  • advanced permissions,
  • GitHub Issues/Projects/Discussions integration,
  • MCP-over-HTTP,
  • full custom branding,
  • real-time collaboration.

Authentication for a deployed read-only site can be handled outside Pony, for example with basic auth at the web server or hosting layer. Pony collects a required name and email in a browser-local profile; this is attribution, not verified identity.

V2 and Later Ideas

These ideas came up during discovery but are intentionally outside the tight v1 scope. They should guide architecture choices so v1 does not close obvious future paths.

Reference-Aware Inbox UI

Keep the global inbox model, but make it easier to reference existing objects from the UI.

Possible interactions:

  • a "comment" or "send message about this" button on each task/doc/card,
  • clicking the button opens the global message box,
  • the message is prefilled with a reference such as TASK-001 or DOC-001,
  • the inbox message still lands in the shared inbox rather than as a direct child comment on the object,
  • the card/doc can later show linked inbox messages as references.

This preserves the product principle that humans do not need to choose the perfect location for feedback, while still making contextual feedback easier.

Linked Feedback on Cards and Docs

V2 can display references in both directions:

  • an inbox message can reference tasks/docs,
  • a task/doc can show related inbox messages,
  • agents can add or adjust links during triage,
  • humans can see which feedback influenced a task or decision.

This should not require moving messages out of the inbox. The inbox remains the global intake stream.

Authenticated or Identified Comments

V1 may rely on external access control and a browser-local name/email profile. V2 can add stronger identity:

  • authenticated users,
  • verified author identity on inbox messages,
  • "edit my own open messages",
  • clearer audit display for who wrote what,
  • optional role/permission model.

Even with auth, normal users do not need direct task-edit permissions. Their primary write capability can remain "send inbox input".

Interactive Web UI Without Direct File Editing

The web UI may become more interactive without becoming the canonical mutation surface for all project state.

Possible v2 interactions:

  • richer inbox submission and editing,
  • filtering/searching/sorting in the browser,
  • acknowledging or following inbox items,
  • commenting with prefilled references,
  • viewing task/doc history or related feedback,
  • lightweight approval/sign-off actions if they map cleanly to core commands.

If browser interactions mutate state, they should still call the same core operations as CLI/MCP/server actions. Do not create a separate web-only behavior model.

MCP Adapter

MCP can ship after the CLI proves the workflow.

V2 MCP direction:

  • pony mcp as stdio MCP server,
  • tools are thin wrappers around core operations,
  • no duplicate validation or file logic,
  • possibly MCP-over-HTTP later if there is a real hosted-agent use case,
  • auth for MCP-over-HTTP should follow the MCP authorization model instead of a custom one.

The first MCP tools should probably mirror the small CLI surface: list/show inbox, claim inbox, close inbox, list/create/move tasks, list/show docs, and get context.

Attachments and Offline Drafts

The browser stores the local author profile in localStorage and the pending message, including file blobs, in IndexedDB. This keeps the profile small while allowing the complete draft to survive a reload.

Inbox messages support up to 10 common image/document attachments, limited to 10 MiB per file and 25 MiB in total. Attachment metadata is stored in the message frontmatter and binary files live in a message-scoped sibling directory. Supported extensions are .png, .jpg, .jpeg, .gif, .webp, .avif, .pdf, .txt, .md, .csv, .json, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .odt, .ods, and .odp.

Richer Documentation Space

The v1 docs area should stay small. Later, the document model can grow if real projects need it.

Possible additions:

  • internal vs shared visibility,
  • richer decision lifecycle,
  • linked decisions and supersession graphs,
  • open-question workflow,
  • generated status/handoff summaries,
  • project glossary,
  • reference library for external links/assets.

Avoid turning docs into a generic wiki until there is concrete pressure.

Configurable Branding

V1 should use a neutral, minimal, shadcn-like design. Later, projects may need light branding for customer-facing deployments.

Possible additions:

  • logo,
  • accent color,
  • light/dark preference,
  • customer/project display name,
  • limited theme tokens.

Keep this shallow; Pony should not become a theme system.

Browser-Based Task Mutation

V1 should not include full task editing in the browser. Later, some interactive task operations may be useful, especially for project leads.

Possible additions:

  • create task from inbox message,
  • approve agent-created task,
  • mark a task as accepted/done,
  • reorder cards,
  • add/remove references,
  • edit task metadata.

Any such mutation must go through core and respect the same schemas, write policy, locks, and git behavior as CLI/MCP.

Better Git Sync and Conflict Handling

V1 write policy can be simple. Real deployments may need stronger sync behavior.

Possible additions:

  • pull-before-write,
  • configurable target branch,
  • retry policy for push failures,
  • clearer conflict UI,
  • background sync status,
  • protected branch workflow,
  • optional commit signing,
  • server-side queue for writes.

Do not overbuild this before the first deployed projects show which failure modes matter.

Installation and Packaging Model

The same @jfrk/pony package has two runtime roles. A global installation is a launcher that owns init, setup, upgrade, top-level help, version reporting, and update checks. A repository-local installation owns all project commands and the web runtime. This keeps onboarding to one package while making every repository's behavior reproducible from its package manifest and lockfile.

pony init creates .pony/, detects npm, pnpm, Yarn, or Bun from the packageManager field or lockfile, and installs @jfrk/pony@^<launcher-version> as a development dependency. An existing dependency declaration keeps its current dependency section and range. If initialization succeeds but package installation fails, .pony/ remains intact and Pony prints the exact command to retry.

The launcher delegates unknown commands instead of keeping a fixed list of project commands. Delegation is allowed only when the local version has the same major version as the launcher and is not newer than it. pony --version reports both versions and compatibility; pony --help combines launcher commands with the command manifest exposed by the local package. These rules prevent a stale launcher from invoking a runtime with assumptions it does not understand.

The package also contains the Pony plugin. pony setup chatgpt safely merges an npm-backed Pony entry into ChatGPT's supported personal marketplace file; the user still chooses Install in the ChatGPT Plugins UI. Pony does not use npm lifecycle scripts to modify ChatGPT configuration.

pony setup codex remains available for users of the optional Codex CLI. It delegates marketplace, installation, and cache management to that CLI.

pony setup claude similarly delegates all discovery, user-scope settings, and plugin-cache mutations to Claude Code. The marketplace metadata is served from the public npm package because Pony's source repository is private, and its versioned plugin entry exposes skills/pony without writing Claude settings or cache files directly.

The package contains a prebuilt server, the web source used internally by static snapshot builds, and skills/pony. Consumer projects do not copy or configure that source.

The published SSR server bundles its complete non-Node dependency closure. Its generated imports therefore cannot drift when a consumer resolves a newer Astro or transitive dependency from the ranges used by Pony's source and static build tooling. Node.js built-ins remain external because the package declares the required Node.js version. The release workflow builds the package, creates the actual npm tarball, installs it in an isolated consumer with the known Astro 7.1.3 and cookie 2.0.1 regression versions, and requires pony start --no-open to reach readiness before publishing.

pony start binds to 127.0.0.1, uses web.port, accepts request bodies up to web.max_request_body_bytes, and opens the browser after the packaged server is ready. The default request limit is 32 MiB so the validated 25 MiB attachment allowance also has room for multipart framing. --port, --host, and --no-open support temporary overrides and headless deployments. Exposing a non-loopback host requires an authenticated reverse proxy because the web app can write project state.

Pressing Ctrl+C stops the launcher and its web process before control returns to the calling terminal. Pony also restores raw input and disables inherited mouse reporting during shutdown. If an older Pony version already left a terminal printing escape sequences after clicks, run that terminal's reset command or open a fresh terminal session once, then upgrade Pony before restarting it.

pony build captures the current .pony/ state in .pony-web/ as plain HTML, CSS, JavaScript, and attachment files. --base makes links work below a chosen deployment path, while --out-dir overrides the generated directory. The snapshot includes shared instructions, inbox messages, and sender addresses, but excludes the profile, message composer, Actions, and every other write path. Upload and rebuild automation remain the responsibility of the surrounding deployment workflow.

Pony contributors run npm run dev in this repository to use Astro's source development mode on the reserved port 45670. Consumer projects never invoke Astro directly; pony build uses the web source shipped in the Pony package.

Production environments that omit development dependencies must either include dev dependencies for Pony operations or move @jfrk/pony to dependencies. Linked installations remain supported during package development. The packaged web server has an explicit Node.js runtime requirement.

If a linked source checkout reports that dist/web/server/entry.mjs is missing, rebuild and refresh the link in the active nvm installation:

nvm use
npm run build
npm link

That recovery applies only to linked development checkouts. If a registry-installed package contains the server build but exits on an unresolved or incompatible import, the published artifact is broken; rebuilding inside the consumer does not repair it. Record pony --version, then install a fixed Pony release or run pony upgrade when one is available.

The repo contains only state/config:

.pony/
  config.yml
  instructions.md
  inbox/
  tasks/
  docs/

The installed package is treated as read-only. Runtime caches, generated indexes, static snapshots, and local lock files must remain outside both .pony/ and the package.

Future Launcher Architectures

The dual-role package is the smallest useful step now. Keep these alternatives available if distribution or compatibility needs change:

  • Global monolith: let one global package execute every project command. This is simple but projects cannot reproduce their CLI behavior independently of the user's machine.
  • Separate thin launcher package: publish a small global launcher distinct from @jfrk/pony. This reduces global install size and clarifies ownership, but introduces another package and release relationship.
  • Local-only CLI: remove the global installation and standardize on npm exec -- pony. This is maximally explicit but gives non-JavaScript users more setup friction.
  • Launcher-managed runtime cache: let the launcher download versions into a user cache and pin the selected version in .pony/. This avoids modifying a host project's package manifest but duplicates package-manager behavior and adds a new cache lifecycle.

A later launcher/runtime protocol version could replace strict product-version comparison. That would allow independently versioned launchers and runtimes once the handshake has enough capabilities to negotiate safely.

Technical Stack

Language and Runtime

Use TypeScript.

The package should be runtime-portable across Node and Bun where practical:

  • ESM package,
  • Node-compatible filesystem/process code,
  • avoid Bun-only APIs in core,
  • use small runtime adapters only where needed.

Web Framework

Use Astro.

Reasons:

  • Astro supports a prebuilt standalone Node server with on-demand rendering.
  • Runtime rendering lets one packaged app use each repository's .pony/ data and project name without rebuilding.
  • Static generation produces a point-in-time read-only snapshot for hosts that cannot or should not run Node.js.
  • Astro content collections/loaders can help with file-backed content.
  • Astro Actions are a good fit for type-safe submit flows in server mode.

Use Astro features where they fit before adding custom code. Add packages where they prevent unnecessary implementation work.

UI

Use a minimal, neutral, shadcn-like visual style.

No theme builder, branding system, or custom accent colors in v1. At most, the project name comes from config.

Interactivity should start with Astro plus small vanilla client-side scripts. React/Svelte islands can be added later for components that genuinely need them.

Schema and Parsing

Use Zod for schema validation and inferred TypeScript types.

Use established packages for Markdown/frontmatter parsing and rendering. Do not hand-roll frontmatter parsing or Markdown rendering.

Markdown with YAML frontmatter is the source format. The implemented context export is Markdown; compact formats such as TOON remain a possible future optimization and must not become canonical storage.

Git

Use the system git CLI for git operations.

Reasons:

  • respects the user's existing git config,
  • works with SSH/auth the way developers expect,
  • avoids reimplementing remote/auth edge cases in JavaScript.

Do not depend on gh or GitHub-specific APIs for core behavior.

High-Level Architecture

@pony/core
  read/write .pony files
  validate schemas
  perform queries
  handle claim/lock state
  apply git write policy
  produce context exports

@pony/cli
  global launcher plus repository-local command runtime
  uses @pony/core
  primary v1 agent interface

@pony/web
  shared Astro pages and components
  prebuilt standalone server with inbox submit
  static snapshot without actions or profile state
  uses @pony/core

@pony/mcp
  future thin adapter over @pony/core
  no separate file or workflow logic

The implementation can be one package internally at first. The important boundary is conceptual: all mutation and validation logic belongs in core, not in individual adapters.

Repository Data Layout

Default layout:

.pony/
  config.yml
  instructions.md
  inbox/
    MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A.md
  tasks/
    TASK-001.md
    TASK-002.md
  docs/
    DOC-001.md

Use stable filenames that do not include titles. Titles change; IDs should not.

Shared Instructions

.pony/instructions.md is Pony's canonical versioned source for shared project instructions. It is separate from repository-level agent files such as AGENTS.md and from customer-visible Pony docs.

Treat the file as public, non-secret project guidance: everyone who can inspect the Pony workspace or static snapshot can read it. Host/system policy and repository instructions have higher authority. Pony instructions provide shared defaults that a specific task or inbox message may refine only when the more specific requirement does not violate that higher-authority policy. Pony does not merge or rewrite conflicting instruction sources automatically.

---
type: instructions
---

Keep changes focused and document non-obvious decisions near the code.

The frontmatter has one fixed field, type: instructions, and unknown fields are invalid. The body contains only the shared instructions and may be empty. New projects receive a minimal empty record. Older projects may omit the file; Pony treats absence as effective empty instructions until the first supported update creates it. pony doctor validates the file when present.

Use pony instructions show to read it and pony instructions update [body] to replace it. Both commands support --json, and updates also accept stdin. JSON output distinguishes a missing legacy file from a present empty record. Updates use the configured write.mode, including isolated commit/push delivery, rollback, and no-op handling without empty commits.

The live Instructions page renders the same sanitized Markdown and saves through the shared core update and write policy. The static snapshot shows that content as visibly read-only. Pony adds no authentication layer for this editor; the hosting environment must restrict access to the live server when required.

IDs

Use a hybrid ID model:

  • Inbox messages: MSG-<ULID>.
  • Tasks: human-readable sequence IDs such as TASK-001.
  • Docs: human-readable sequence IDs such as DOC-001.

Inbox uses ULID rather than UUID so files sort roughly chronologically in a directory listing. created_at remains the source of truth for timestamps.

Inbox ULIDs are generated by the client before submit. This allows local pending state and idempotent retries.

Task IDs are display identifiers, not globally unique identities. Before task creation, Pony makes a best-effort fetch of the current branch's configured upstream and allocates after the highest task number visible locally or in that ref. A missing repository/upstream or failed fetch warns and falls back to the local files; another clone can still allocate the same number after the fetch. The confirmed longer-term direction is an immutable ULID-based task identity for structured relationships while TASK-NNN remains a human-readable, renumberable display ID. That schema migration is not implemented yet.

File Formats

Inbox Message

Inbox messages are visible to everyone and are the only user-created content in v1.

Path:

.pony/inbox/MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A.md

Example:

---
id: MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A
type: inbox_message
status: open
author_name: "Anna Andersson"
author_email: "[email protected]"
created_at: "2026-07-05T12:00:00Z"
updated_at: "2026-07-05T12:00:00Z"
claimed_by: null
claimed_at: null
references:
  tasks: []
  docs: []
attachments:
  - name: "launch-copy.pdf"
    path: "MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A.attachments/001-launch-copy.pdf"
    media_type: "application/pdf"
    size: 48321
    sha256: "15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225"
---

I am not sure whether the launch copy on the start page matches what we agreed
in the last meeting.

Inbox records created before the titleless format are intentionally not read by this version. Migrate them manually by removing title from frontmatter and, when the title contains information that is not already in the message, prepend that text to the Markdown body. Add attachments: [] and a non-null author_email to every migrated record.

Suggested statuses:

  • open: user can still edit the message.
  • claimed: an agent has started working on it; user edits are no longer allowed.
  • closed: triage is complete.

An agent claim should set status: claimed, claimed_by, and claimed_at immediately. This avoids having to solve branch/version conflicts in v1.

User edits before claim can update the same file. Git history is the audit trail for original content and edits. No separate append-only revisions are needed in v1.

Task

Path:

.pony/tasks/TASK-001.md

Example:

---
id: TASK-001
type: task
title: "Implement customer inbox submit flow"
status: backlog
priority: soon
assignee: null
created_at: "2026-07-05T12:00:00Z"
updated_at: "2026-07-05T12:00:00Z"
references:
  inbox:
    - MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A
  docs: []
---

## Context

Customers need a simple way to send project feedback without choosing the right
card.

## Requirements

- Add a global inbox submit form in the packaged server app.
- Store the complete pending message in IndexedDB until the server confirms it.
- Write one inbox file per submitted message.

## Acceptance Criteria

- [ ] A submitted message creates a `.pony/inbox/MSG-*.md` file.
- [ ] The server returns the path and git commit SHA.
- [ ] The client clears the pending IndexedDB state only after confirmation.

Default task statuses are:

  • triage
  • backlog
  • in_progress
  • review
  • done

Use triage for preliminary cards that still lack required intent, scope, constraints, decisions, or success criteria. Move a card to backlog only when it has a localized user story or goal, acceptance criteria, scope, and the necessary confirmed decisions. Keep selected work in backlog until implementation starts, then move it to in_progress.

The exact status list is configurable in .pony/config.yml. Existing projects that configure todo remain unchanged and continue to support it. Projects with the exact pre-triage default list gain triage during normalization while keeping todo for compatibility; custom status lists are preserved unchanged. Migrate explicitly with pony task rename-status todo backlog. The command updates matching task files and removes todo from the configured statuses, merging into the existing backlog entry when present.

Task priority describes when work should flow through the configured statuses:

  • asap: precedes every other eligible task regardless of status.
  • soon: precedes normal and later work within the same status.
  • null: the persisted default, shown as In turn, follows normal Kanban ordering. CLI inputs in_turn and null both store this value.
  • later: follows every other eligible task regardless of status.
  • not_planned: is excluded from work selection and ordinary Board/Done views.

These values and semantics are fixed Pony behavior rather than project configuration. Use pony task prioritize TASK-001 <priority> to change only the scheduling priority. Within each status column, Pony sorts cards by asap, soon, In turn, and later, then by oldest created_at and task ID. Only explicit ASAP, Soon, and Later labels appear on ordinary cards; task detail pages always show the complete priority.

Not-planned tasks retain their workflow status and appear in the Archive view, which uses the same configured status columns as the primary board. Assigning a new priority restores the task to its retained column. Archive is therefore not a workflow step after Done; remove a task file when the record itself should no longer be retained.

Projects created before semantic priorities remain readable in legacy mode. Inspect the required explicit decisions before migrating:

pony task migrate-priorities --inspect
pony task migrate-priorities \
  --map high=soon \
  --restore TASK-042=backlog

Repeat --map for every legacy priority and --restore for every task whose legacy status is archived. Pony suggests common mappings but never applies them without confirmation. Migration validates all target priorities and statuses before writing, updates the files atomically through the configured write policy, removes the legacy archived status, and records priority_model: scheduling_v1. pony doctor reports readable legacy values as migration diagnostics until this is complete.

Document

Docs are customer-visible project context, not an attempt to build a complete knowledge base in v1.

Path:

.pony/docs/DOC-001.md

Example:

---
id: DOC-001
type: decision
title: "Use a global inbox instead of card comments in v1"
status: active
visibility: shared
created_at: "2026-07-05T12:00:00Z"
updated_at: "2026-07-05T12:00:00Z"
superseded_by: null
---

Customers often do not know where feedback belongs. All human input should
therefore go to a global inbox first. Agents can later link inbox items to
tasks, docs, or decisions.

Suggested document types:

  • brief
  • decision
  • question
  • reference
  • note

Suggested document statuses:

  • active
  • resolved
  • superseded

Decision documents should support superseded_by so outdated decisions are not silently treated as current.

Config

Path:

.pony/config.yml

Example:

schema_version: 1

project:
  name: "Project name"
  language: en

web:
  port: 4567
  max_request_body_bytes: 33554432

write:
  mode: working_tree
  branch: current
  commit_author:
    name: "Pony Inbox"
    email: "[email protected]"

tasks:
  statuses:
    - triage
    - backlog
    - in_progress
    - review
    - done
  priority_model: scheduling_v1

Write modes:

  • working_tree: write files but do not commit. Best for local development.
  • commit: write files and create one local commit per changing mutation, but never push. Pony requires an existing initial commit and a checked-out named branch. branch: current accepts that branch; any other value must exactly match it.
  • commit_and_push: write files, commit, and push. Best for a deployed customer-facing Pony server. The checked-out branch must already have an upstream and exactly match its local tracking ref before each mutation.

Commit delivery checks every mutation target against HEAD before writing. Existing targets must be tracked and clean in both the working tree and index, while new targets must not already exist. Unrelated modified, staged, and untracked files are preserved. Pony builds the commit with a temporary index, includes only the declared mutation files, applies commit_author without changing Git config, and returns the full commit SHA. It never creates or switches branches, signs a commit, or runs repository hooks. Task creation may already have performed the worktree-preserving upstream fetch described under IDs.

Filesystem writes and commit delivery form one transaction. If Git cannot create the commit, Pony restores existing files byte-for-byte and removes files or attachment directories created by the mutation. An error explicitly reports when that rollback also fails. Idempotent no-change results return a null SHA without running Git preflight or creating an empty commit.

Commit-and-push mode uses the same isolated commit transaction, then pushes the new SHA explicitly to the checked-out branch's configured upstream remote ref. It does not infer origin, use push.default, configure an upstream, or push another ref. Pony makes one push attempt and runs no local Git hooks.

If push fails, the local commit and mutation files remain intact. The error includes the retained SHA, destination, and an exact retry command. Pony never rolls the commit back, force pushes, pulls, merges, or rebases as part of delivery. A branch that is already ahead, behind, or diverged from its upstream is rejected before the first file write; ahead errors include the pending push command, while behind and diverged errors require manual fetch and reconciliation. Successful no-change operations still return a null SHA without running Git or contacting the remote.

.pony/config.yml provides project defaults. CLI flags and environment variables should be able to override runtime/deployment-sensitive settings, especially write mode. This decision should be revisited after the MVP has been used in real projects.

project.language is a canonical BCP 47 tag for new human-readable task and doc content. pony init --language sv-se stores sv-SE; omitted values default to en, including legacy configs without the field. It does not localize Pony's UI, CLI messages, structured frontmatter, or existing records. Inbox text is always preserved in the language submitted by its author.

web.max_request_body_bytes defaults to 33554432 (32 MiB). Values must be positive whole bytes and cannot exceed 268435456 (256 MiB), Pony's framework transport ceiling.

Inbox Submit Flow

Server-backed submit flow:

  1. Browser creates a ULID and message ID: MSG-<ULID>.
  2. Browser stores the draft and file blobs in IndexedDB.
  3. Browser submits the payload as multipart form data.
  4. Server validates identity, content, attachments, and message ID format.
  5. Server checks whether the target file already exists.
  6. If the file exists with the same payload, return success with the existing path/commit where possible.
  7. If the file exists with different content, return a conflict.
  8. If the file does not exist, write the inbox file and attachment directory.
  9. Apply the configured write policy.
  10. Return path, commitSha when a commit was created, and structured Git delivery state describing whether commit or push actions remain.
  11. Browser clears pending IndexedDB state only after confirmation.

There should be one git commit per incoming inbox message in commit and commit_and_push modes.

Suggested commit message:

feat(inbox): add message MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A

For edits before claim:

fix(inbox): update message MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A

For claims:

chore(inbox): claim message MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A

Browser Behavior

The browser UI stores the required name/email profile in localStorage and the complete pending submission in IndexedDB.

Reasoning:

  • Web Storage is sufficient for the small profile record.
  • IndexedDB can persist structured draft data and file blobs.
  • The pending message ID remains stable across reloads and retries.

The UI should make pending state explicit:

  • "Saving..."
  • "Saved in commit <sha>"
  • "Still pending, retry"
  • "This message has been claimed and can no longer be edited"

Web UI V1

Pages/views:

  • Project overview
  • Kanban board, read-only
  • Inbox, visible to everyone
  • Documents, read-only list/detail
  • Shared instructions, editable in the packaged server
  • Global "send message" box

Packaged server behavior:

  • render the same UI,
  • enable inbox submission,
  • apply write policy,
  • read project state and branding from .pony/ at request time.

Static snapshot behavior:

  • render board, tasks, docs, shared instructions, inbox messages, sender addresses, and attachments,
  • mark shared instructions visibly read-only,
  • omit profile, message submission, Actions, and all write paths,
  • support deployment at the web root or below a configured base path,
  • write a self-contained directory for an external deployment workflow.

V2 can add UI shortcuts from cards/docs into the global message box, for example pre-filling references such as TASK-001. V1 does not need comments directly attached to cards.

CLI

Use one binary/command with subcommands.

The globally installed binary acts as a launcher. It can initialize a project, configure integrations, report global/local versions, and discover local commands. Once .pony/config.yml and a compatible local package are present, it delegates every project command to that package.

Current command surface:

pony setup chatgpt
pony setup claude
pony setup codex
pony upgrade
pony upgrade --launcher-only
pony upgrade --project-only
pony init --name "Project name" --language en
pony --version
pony --help
pony start
pony build --base /projects/example/
pony doctor
pony doctor --json

pony instructions show
pony instructions show --json
pony instructions update "Shared instruction body"
printf '%s\n' "# Shared rules" "" "Keep changes focused." | pony instructions update

pony inbox list
pony inbox show MSG-...
pony inbox add "Message" --email [email protected] --attachment ./brief.pdf
pony inbox claim MSG-... --by "Agent name"
pony inbox close MSG-...
pony inbox link MSG-... --task TASK-001

pony task list
pony task show TASK-001
pony task create "Task title" "Task body" --status triage
pony task move TASK-001 in_progress
pony task prioritize TASK-001 asap
pony task rename-status todo backlog
pony task migrate-priorities --inspect
pony task update TASK-001 "New body" --title "New title"
pony task link TASK-001 --inbox MSG-... --doc DOC-001
pony task renumber TASK-001 TASK-010
pony task shift TASK-010 --by 2
pony task conflict TASK-016 --json
pony task resolve-conflict TASK-016 --move-stage 3 --to TASK-025

pony docs list
pony docs show DOC-001
pony docs create "Doc title" "Doc body" --type note
pony docs update DOC-001 "New body" --title "New title"

pony context --format markdown

After pony inbox add, Pony reports whether the configured write mode leaves the message waiting for a commit or push. In the default working_tree mode, the browser and human-readable CLI output include a ready-to-use message such as:

Git reminder: commit and push this message. Suggested commit: feat(inbox): add message MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A

pony inbox add --json exposes the same state without mixing prose into the JSON document:

{
  "gitDelivery": {
    "writeMode": "working_tree",
    "commitRequired": true,
    "pushRequired": true,
    "suggestedCommitMessage": "feat(inbox): add message MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A",
    "suggestedCommitBody": "Add MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A at .pony/inbox/MSG-01JZ7M8E6R4D9W0M4X3N2P1Q8A.md."
  }
}

The object is part of the full inbox result; unrelated record fields are omitted from this example. commit requires only a push, while commit_and_push requires neither action and therefore adds no human-readable Git reminder.

pony doctor validates .pony/config.yml, the optional canonical instructions, and every inbox, task, and doc frontmatter record without stopping at the first malformed file. It prints a human-readable report and exits with status 1 when violations exist. pony doctor --json returns a versioned report with relative file paths, record types, field paths, Zod issue codes, structured issue details, and messages for agents and scripts. Run it again after repairs until valid is true.

CLI output supports:

  • human-readable table output,
  • JSON for scripts,
  • Markdown context output for agents.

The CLI is the primary v1 interface for AI agents.

Concurrent Task ID Recovery

Automatic allocation is best-effort and does not reserve an ID. Before pushing concurrent work, fetch and inspect the combined history. During an interactive rebase, use pony task renumber for one exact move or pony task shift to make space for a range, then review the reported textual occurrences and continue the rebase yourself. Pony updates filenames, task frontmatter, and structured Pony-owned task references; it never rewrites Markdown titles/bodies, Git history, commit messages, or external links.

For an active add/add conflict, inspect the index with pony task conflict TASK-NNN. Stage 2 is Git's ours variant and stage 3 is theirs; titles and creation times help identify each task. Resolve by moving one variant to a free ID:

pony task resolve-conflict TASK-016 --move-stage 3 --to TASK-025
git merge --continue

During an active merge or rebase, Pony recovery commands stage only their declared .pony files, create no commit, perform no push, and leave the relevant git merge --continue or git rebase --continue to the user. Existing references to the shared add/add ID are ambiguous and remain untouched for manual review.

The skill in skills/pony/SKILL.md ships with the npm/plugin release. Editing that source file does not mutate an already installed Codex, ChatGPT, or Claude plugin cache. Install or upgrade the matching release and reload the integration when the host requires it before expecting agents to use newly documented commands.

MCP

MCP is not required to prove the first MVP. It should be designed in, but can ship later as a thin adapter.

If included early, keep it minimal:

  • stdio transport only,
  • no MCP-over-HTTP,
  • no separate auth model,
  • no separate file logic,
  • tools just call the same core operations as the CLI.

Possible first tools:

  • list_inbox
  • get_inbox_message
  • claim_inbox_message
  • close_inbox_message
  • list_tasks
  • create_task
  • move_task
  • get_context

Agent Workflow

The intended agent loop:

  1. Read project rules and current context.
  2. List open inbox messages.
  3. Claim one inbox message before doing triage.
  4. Interpret the message according to project guidelines.
  5. Create incomplete cards in the configured triage status. Ask one question at a time and confirm intent, scope, constraints, and success criteria before promoting them to backlog.
  6. Link it to existing tasks/docs, create a new task, create/update a doc, or close it as handled.
  7. Leave a clear trace in files and git commits.

Agents should not silently rewrite user-submitted messages after claim. If a message needs interpretation, put that interpretation in task/doc metadata, links, or agent-created notes/docs, not by changing the user's words.

Documentation Surface

The document area is intentionally small in v1. It exists so customers and PMs can understand the board and inbox without reading the source repo.

Useful doc categories:

  • project brief/scope,
  • decisions,
  • open questions,
  • references,
  • notes.

Internal agent knowledge should stay outside the customer-facing docs, for example in repository instructions or implementation files. Pony may later support internal visibility more formally, but it is not required for v1.

Deployment Modes

Local Development

Typical write mode: working_tree.

The app writes files but does not commit or push unless explicitly configured.

Local Agent Workflow

Possible write mode: working_tree or commit.

This lets agents mutate .pony/ through CLI while the human controls when changes are committed/pushed.

Customer-Facing Server

Typical write mode: commit_and_push.

The server receives inbox submissions, writes one file per message, commits, and pushes so the published/read-only view can update.

Authentication can be handled by the web server/hosting layer in v1. Pony itself should avoid building a full auth system until it has a clearer need.

Important Technical Decisions So Far

  • Use shared Astro views for the packaged server and static snapshot.
  • Install as a package; do not copy app source into each project repo.
  • Let pony build render project-specific static output from packaged source.
  • Treat one Pony server process as bound to one .pony/ workspace.
  • Render project.name and project state at request time in server mode and at build time in static mode.
  • Treat package contents as read-only and keep session state in memory.
  • Bind the web server to loopback unless external exposure is explicit.
  • Version the .pony/config.yml schema independently of the package version.
  • Store project state in .pony/.
  • Use Markdown with YAML frontmatter as canonical storage.
  • Keep generated context exports separate from canonical Markdown storage.
  • Use Zod for schemas.
  • Use established packages for parsing/rendering.
  • Use system git CLI.
  • Use TypeScript, compatible with both Node and Bun where practical.
  • Use a single CLI command with subcommands.
  • Use the same npm package as a global launcher and repository-local runtime.
  • Let the launcher own initialization, setup, help, and version reporting.
  • Require the local runtime to share the launcher's major version and not be newer than the launcher.
  • Make CLI the primary v1 agent interface.
  • Treat MCP as a future/thin adapter over core.
  • Use a global inbox, not card-specific comments, in v1.
  • Make all inbox input visible to everyone.
  • Let users edit inbox messages only until an agent claims them.
  • Use git history as audit trail for edits.
  • Use ULID for inbox message IDs.
  • Use stable task/doc filenames without titles.
  • Commit one inbox message per commit when commit mode is enabled.
  • Make write policy configurable and overrideable.

Future Decisions

These remain deliberately undecided until real project usage provides stronger requirements:

  • Whether docs should support visibility: internal.
  • Whether .pony/locks/ is needed at all, or whether persistent claim state in frontmatter plus process-level file locking is enough.
  • Whether a future delivery queue should add scheduled push retries beyond the current explicit, idempotent retry command.
  • Whether pony init should offer to add instructions to root AGENTS.md, or only create .pony/agent-guide.md.
  • When the launcher/runtime handshake should move from product-version checks to an independently versioned capability protocol.