Download the PHP package pigagent/pig without Composer

On this page you can find all versions of the php package pigagent/pig. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package pig

pig — PHP AI Agent

English · 简体中文

A PHP port of pi, the agent harness whose coding agent runs on a famously small core. Same architecture, same file layout, written for PHP 8.3 with no runtime dependencies — no Guzzle, no ReactPHP, no amphp, no ncurses. Just the standard library.

Status: it runs. bin/pig is a coding agent you can talk to in a terminal: streaming answers, tools with live output, edits shown as diffs, Escape to interrupt, typing while it works, and !cmd to run a shell command the model can then see (!!cmd keeps it out of the conversation). Sessions are saved as they happen — --continue picks up the last one, /resume picks from a list. When the context fills it summarises itself and carries on, which /compact also does on demand, and /model switches models mid-session. Skills are picked up from ~/.pig/agent/skills and from Claude's and Codex's folders too, and images a tool returns are drawn in the terminal. Hooks are PHP files that can block a tool, edit what the model is shown, or add commands of their own, and a folder with an index.php in it is a tool the model can call. -p prints one answer and exits, and --mode json or --mode rpc drops the terminal for JSON lines, for an editor.

Packages

Package Namespace State
pig/async Pig\Async\ Event loop, futures, coroutines — done
pig/ai Pig\Ai\ Unified LLM API — Anthropic, OpenAI chat-completions, OpenAI Responses and Gemini all stream end to end
pig/agent-core Pig\Agent\ Agent loop with tool calling, JSON Schema validation of tool arguments, and state — done
pig/tui Pig\Tui\ Terminal UI with differential rendering — done
pig/coding-agent Pig\CodingAgent\ Coding agent — tools, prompt, interactive CLI, saved sessions, compaction, model switching, skills, hooks, custom tools and all three modes (terminal, print, RPC) done

pig/async has no counterpart upstream: JavaScript ships an event loop and PHP does not. It exists so one stream_select() can wait on the model's socket and on the keyboard at the same time, which is what makes interrupting a running turn — and typing while the model streams — possible at all.

Behind a proxy, which some networks require to reach a provider at all:

HTTP CONNECT and SOCKS5, with a username and password if the proxy wants one. TLS starts after the tunnel is open and verifies the provider's certificate, so the proxy carries the bytes and can read none of them; a hostname is handed to the proxy to resolve, because a local resolver is often the other thing that does not work. Loopback always goes direct, no_proxy and proxy.bypass add to that, and --no-proxy turns the lot off.

CodingAgent::session() is the whole of startup as a call: it resolves the model and the thinking level, loads the skills, context files, hooks and custom tools, opens or creates the session file, and hands back a session plus a list of warnings. bin/pig is a caller of it rather than the place it lives, so the resolution order can be tested instead of run and looked at.

A different thing with the same name: Agent\StreamProxy sends the conversation to a gateway server that holds the provider keys and makes the call, speaking upstream's /api/stream wire format so a gateway written for pi works unchanged. Nothing turns it on — it is a streamFn you pass in — because it hands the conversation to whoever runs that server, which is the point for a team that wants no keys on laptops and a reason to avoid it otherwise.

A tool call is checked against the tool's own JSON Schema before it runs — Ai\Utils\JsonSchema is a draft-07 subset with AJV's wording, because the reader of a validation failure is the model that has to correct itself from it. An unknown keyword is ignored rather than failed, so adding a keyword to a tool's schema can never break the tool.

Try it

The installer checks PHP and its extensions before touching anything, installs the package with Composer, and offers to put Composer's global bin directory on your PATH — which is the step that is otherwise easy to miss, because Composer says nothing about it and pig is then command not found.

Composer directly works too, with that last step left to you:

To work on pig itself, clone it instead — everything below is the same either way, with bin/pig in place of pig:

--read-only takes away edit, write and bash; --theme light for a light terminal; --api-key <key> uses a key for this run only, without saving it; -c/--continue to pick up where you left off, or -r/--resume on its own to choose from a list — type in that list to search it, and the search matches anything said in the conversation, not just the line it opened with. Escape there starts a new conversation instead; ctrl+c leaves without starting one. --session <id> resumes an earlier session by its ID or path directly (printed upon quitting a session). /resume inside a session shows the same list, search and all. -h for the flags, -v for the version. /help inside lists every key, the prompt's own editing keys included, and every command. /reload reloads extensions, skills, commands, tools, and context files (CLAUDE.md / AGENTS.md) live without restarting pig (upgrading pig's core code itself still requires restarting the process). Shift+ctrl+d writes a debug log — the frame, how wide each line came out, and the conversation — which is the thing to attach to a bug report.

A start asks Packagist once, in the background, whether there is a newer pig, and says so under the conversation if there is — with the update command (pig update). Nothing is said when the answer is no, when the network is not there, or when anything else goes wrong. Run pig update anytime to self-update pig to the latest release (or pig update --models to refresh model catalogs). --no-update-check skips the asking for one run, and "update": {"check": false} in ~/.pig/agent/settings.json turns it off for good. /changelog shows what changed, and the entries newer than the version you last saw are shown once, by themselves, after an upgrade.

With a Claude Pro or Max subscription there is no key to set: /login gives you a URL to open and takes the code that comes back. A GitHub Copilot subscription works the same way — it shows a code to type at github.com and waits, and escape stops the waiting. Antigravity is the third: it opens a browser and catches the redirect on localhost:51121, so that port has to be free, and it needs a client id and secret of its own, which pig does not ship — set ANTIGRAVITY_CLIENT_ID and ANTIGRAVITY_CLIENT_SECRET, or antigravity.clientId and antigravity.clientSecret in ~/.pig/agent/settings.json. It is what gets you Gemini 3, Claude and GPT-OSS through a Google subscription. Whichever you use, the token is kept in ~/.pi/agent/auth.json — pi's own file, when pi has one, so signing in once is signing in once. /logout forgets it.

There is also bin/pig-ai login — the same four sign-ins from a plain command line, for a machine you are setting up over ssh. bin/pig-ai list names them.

If that directory still has an old pi's oauth.json in it, pig moves it across on the first run and says which providers it moved — the old file is renamed, not deleted.

Anything that is not an option is a message, and @some/file is read in front of it:

An image goes in as an image, so a screenshot reaches the model without a tool call. -- ends the options, for a message that starts with a dash or an @.

Ctrl+G opens whatever is in the prompt in $VISUAL or $EDITOR and puts the result back — for the message that turned out to be three paragraphs. It works while the model is still answering: the editor gets the terminal, and the answer keeps arriving behind it.

Typing while the model works is the point of the event loop, and there are two keys for it, upstream's: Enter steers — the message goes in after the tool that is running, for "no, the other file" — and Alt+Enter (Option+Enter) queues a follow-up for after the turn. Each waits above the prompt as Steering: or Follow-up:, and Alt+Up takes them all back into the editor without stopping anything; escape takes them back and stops the turn.

The model gets four tools by default — read, bash, edit, write — which is upstream's set; --tools read,grep,find,ls names the set outright, and --read-only swaps in the read-only four. Fewer tools is deliberate: a model with seven spends part of every turn choosing between them, and searching through bash with rg is what the prompt already asks for.

--model takes a part of a name rather than a whole id — --model sonnet, --model 'opus 4.1' — and --model sonnet:high sets the thinking level at the same time. --list-models lists the ones you have a key for, with their context and output limits; --list-models gem pro narrows that, fuzzily, over the provider and the id together. /model offers the same list, and switching to a model with no key is refused by name rather than failing on the next turn. Ctrl+L opens that list; Ctrl+P steps to the next model on it without opening it, Shift+Ctrl+P back to the previous one.

--models narrows the session to a few of them, comma-separated, and then Ctrl+P walks only those: --models sonnet,haiku opens on sonnet and cycles between the two, and --models 'anthropic/*:high' takes every Anthropic model with thinking set high for each. A pattern may be a glob or a part of a name, and :level on the end sets the level for that entry. /model offers the scope too, so the list and the keystroke agree about what is on offer.

171 models are known: Anthropic's, OpenAI's own on the Responses API, Gemini, and Groq, Cerebras, xAI, Zai and Mistral, which all speak OpenAI chat-completions. Set the matching *_API_KEY and --model reaches them.

GitHub Copilot's nineteen are there too, and Antigravity's fourteen — the models those subscriptions serve, under the same ids their own providers use. So gpt-5 and claude-sonnet-4-6 name two models each: a bare name means the direct provider, and a subscription's is --model github-copilot/gpt-5 or --model antigravity/claude-sonnet-4-6.

/label before the refactor names where you are, and /tree shows the name beside what was said — pi's own label entries, so a name set in either tool shows up in the other.

/tree goes back to an earlier point in the conversation and carries on from there. It draws the whole conversation as a tree, forks and all, so the road not taken is a row you can move the cursor onto rather than something the file merely still contains:

• marks the path you are on. Ctrl+O cycles five filters (everything, no tool results, only what you said, only what you named, absolutely everything), typing searches — what you have typed is on the Search: line above the rows — and l names the row under the cursor. Going back offers to summarise the branch you are leaving, so an hour of exploring arrives on the branch you are joining instead of being left behind. Going back to something you said takes it out of the conversation and puts it back in the prompt, to be asked differently.

Sessions are written in pi's own format, in pi's own directory layout — so a conversation started in one opens in the other, and --resume lists what is in ~/.pi/agent/sessions/ beside pig's own. Carrying on from a pi session appends to that file, in that format.

Resuming brings back the model and the thinking level that conversation was being had with, not whatever a new one would open with. --model still wins if you name one.

/changelog shows what changed release by release, and new entries are shown once after an upgrade (not when you resume a conversation).

/export writes the conversation out as one self-contained HTML file — markdown rendered, code highlighted, no JavaScript in it at all. pig --export <session.jsonl> [out.html] does the same to a session on disk without opening it.

/bug [what went wrong] writes a bug report — pig, PHP and OS versions, the model and provider (never a key), the last provider error, /doctor's findings, the last few crashes, and the transcript only if you say yes — to ~/.pig/agent/bug-reports/, copies it, and opens a GitHub issue with it prefilled. Nothing leaves the machine unless you open that link. When pig itself falls over, the crash is written down and the next start says so, with /bug as the way to report it.

A turn that fails because the provider is busy — a 429, a 503, a socket that died — is waited out and sent again, doubling from two seconds, up to three times, with what the provider said and a countdown on screen and escape to stop. When the provider names the moment its quota comes back, that is the wait instead of the doubling — coming back in two seconds to a quota that resets in forty is three more refusals. Past a minute it is not waited out at all: the turn ends with what the provider said, because a retry that resumes after lunch is not a retry. A turn that fails because the conversation outgrew the model's window is a different thing and is treated as one: it is summarised first, then sent again, because the same request would be exactly as long in four seconds. Escape stops that summarising as well, and stops it whether it was /compact that asked or a full window. retry.enabled: false in the settings turns the first off.

A provider pig has never heard of goes in ~/.pig/agent/models.json — your own box, a proxy, a local server — and its models then work everywhere a built-in one does, including --model, /model and --list-models:

apiKey is the name of an environment variable if one answers to it, so the key itself need not be in the file — and an all-capitals name with no variable set is treated as no key at all, said at startup by name, rather than being sent to the endpoint as though it were the key. A model may carry a "cost": { "input": …, "output": …, "cacheRead": …, "cacheWrite": … } block, in dollars per million tokens — so three dollars per million is 3.0, not 0.000003 — and leaving it out means free, which is what a local model is. A price that is not a number is named and the model skipped, rather than quietly costing nothing in /session and the footer. api is one of openai-completions, openai-responses, anthropic-messages or google-generative-ai, and can be set on the provider or per model; authHeader: true sends the key as Authorization: Bearer … for a proxy that wants it there. Anything wrong with the file is printed and skipped — the rest of it, and every built-in model, still work. It is pi's format, and pi's own ~/.pi/agent/models.json is read when pig has none.

Settings live in ~/.pig/agent/settings.json, and a project can override them in .pig/settings.json. The theme, model and thinking level you pick are remembered. /settings shows what can be changed from inside a session — theme, thinking, whether reasoning is drawn, whether pictures are drawn, whether messages you type mid-run go over one at a time or together, auto-compact, auto-retry — with what each one is set to now. Enter changes the row you are on and the list stays open; escape closes it.

The keys the application takes — escape, ctrl+c/d/z, shift+tab, ctrl+p, ctrl+l, ctrl+o, ctrl+t, ctrl+g, alt+enter, alt+up — can be moved in ~/.pig/agent/keybindings.json, under pi's action names and key spelling: {"app.model.select": "ctrl+m", "app.tools.expand": ["ctrl+e", "shift+ctrl+o"]}. A binding replaces the default, so moving ctrl+o frees it for tmux; [] unbinds; the help shows the keys that actually work; a key or action the file names wrong is a line on the shell at startup.

A markdown file in ~/.pig/agent/commands/ or .pig/commands/ becomes a slash command: review.md is /review, its body is the prompt, and $1 and $@ are filled from what follows. Those and the ones a hook registers work outside the terminal too — pig -p "/review src/Foo.php" sends the prompt, and pig -p "/deploy staging" runs the hook's command.

A PHP file in ~/.pig/agent/hooks/ or .pig/hooks/ that returns a callable is a hook. It gets sixteen events — every tool call and result, every turn, the context on its way to the model, compaction, /tree, startup and shutdown — and can block a tool, rewrite what the model is shown, or add a slash command of its own:

A hook can also say something — $pi->sendMessage('build', 'the tests are failing') puts it in the conversation where the model reads it, with display: false if it is for the model and not for you, and triggerTurn: true to have the agent answer it there and then. A hook can draw its own messages with registerMessageRenderer(). And $pi->appendEntry('permissions', $data) writes something into the session file that the model never sees — hook state that is still there after a restart, costing no context.

A hook runs inside pig, so it can hand back an object and reach pig's own classes — and a hook that loops or calls exit() takes the session with it. Broken ones are named on the shell at startup rather than crashing; /hooks lists what loaded and --no-hooks skips them.

Which is why a project's own .pig/ is not loaded until you say so. The first time pig opens a directory that has one — hooks, tools, extensions, skills, commands or a settings.json under .pig/, or extensions/ with PHP in it — it asks whether to trust the project, and remembers the answer in ~/.pig/agent/trust.json (trust a parent folder once and every checkout under it is covered). An untrusted project keeps its .pig/ out and says so on screen; your own ~/.pig/agent/ is always yours. /trust changes the saved decision, and with no terminal to ask on (-p, --mode json|rpc) an undecided project is untrusted, so a script run in a stranger's repository cannot run that repository's hooks.

A hook can also ask, mid-turn, and wait for the answer:

The tool call parks, a picker appears, and the keystroke resumes it — the handler gets a plain bool back. select, input, a multi-line editor, notify, a keyed footer line and custom (draw your own component) are there too. Escape answers no, so walking away from the question does not wave the tool through.

A folder with an index.php in ~/.pig/agent/tools/ or .pig/tools/ is a tool the model can call — a folder, because that directory also holds the fd and rg binaries pig may have downloaded, and a file there is one of those. Same loader as hooks, same trade-off; /tools lists everything the model has and where each one came from, and --no-tools skips them:

$ctx is the session: the conversation so far, which model is answering, whether the agent is busy, a way to stop it, and the same ui a hook gets. A tool can also be told when the session starts, switches, jumps or ends, which is how one that keeps state rebuilds or lets go of it. And it can draw its own call and its own result in the transcript, so a tool whose answer is a table is not squeezed through formatting meant for files.

An extension is a PHP file (or a folder with index.php) in ~/.pig/agent/extensions/, .pig/extensions/ or extensions/ that unifies hooks, commands and tools into a single definition. The factory is given an ExtensionApi, which inherits HookApi and adds registerTool(). --no-extensions skips them, and --extension <path> loads an explicit file.

Skills are folders with a SKILL.md in them. pig reads ~/.pig/agent/skills and .pig/skills, and also ~/.claude/skills, .claude/skills, ~/.codex/skills, ~/.pi/agent/skills and .pi/skills, so a skill written for another agent — or for pi, before the move — works here unchanged. Two folders holding the same name is an override rather than an error: pig > pi > claude > codex, a project folder beats the home one, and --skills-dir beats all of them. /skills lists what was found and where each one came from, and the startup says which file an override took the name from; --no-skills loads none of them, as --no-hooks and --no-tools do for theirs. The five folders another tool owns can also be turned off one at a time, under upstream's own settings keys — skills.enableCodexUser, enableClaudeUser, enableClaudeProject, enablePiUser, enablePiProject — which is what to reach for when a large ~/.claude/skills does not belong in front of the model. pig's own two folders have no such key: skills.enabled and --no-skills are the switch for those, and skills.ignoredSkills takes glob patterns for anything narrower.

Rpc\RpcClient is the other end of --mode rpc: it starts the agent, sends the twenty-two commands and hands back events, with every call suspending its own fiber rather than returning a promise — so a host reads like a program that blocks, and nothing blocks.

There are three ways in, and the terminal is only the default. -p says it, prints the answer and exits — for a shell script, or a pipe:

--mode json is the same run with every event on standard output instead: the streaming a terminal would draw, for something that wants to parse it. Warnings stay on standard error, so the lines are all JSON.

--mode rpc reads commands as JSON lines and never stops: for an editor, or anything else driving pig from code.

--mode web launches an interactive browser-based chat interface matching pi-web with zero external dependencies (pure PHP non-blocking WebSocket & HTTP engine, two-level workspace directory and session drawer, telemetry status bar, and real-time full-duplex RPC streaming):

You can also type /web from inside any interactive terminal session to launch the web interface on the fly.

To keep it running after you close the terminal, run it as a daemon:

pig web start without -d is the same as --mode web in the foreground. No framework behind it: pcntl_fork() twice, posix_setsid(), a pid file — so ext-posix is needed for -d and stop, and nothing else changes.

Every conversation you open in the browser gets a tab above the chat — labelled by its name or its first line, working dot indicators while an agent streams, × to close, + for a new one — persisted in the browser across reloads. The web shell follows pi-web's process model: each conversation is backed by its own isolated pig --mode rpc child process in a managed pool (SessionPool), so tabs run true parallel tasks concurrently without interfering with each other's stream or tools. When launched via /web from inside the terminal, the terminal's own session stays entirely separate.

A hook that asks — a tool_call guard's confirm(), a select, an input, an editor — asks in the page when pig was started with --mode web: the question goes out over the WebSocket as the same hook_ui_request line RPC mode uses, a dialog opens, and the answer resumes the parked tool call. Escape is no. Started from inside the terminal with /web, the terminal stays the place hooks ask, because two places asking one question is one too many.

The accounts button (or /accounts) opens the Antigravity accounts the pig-antigravity extension keeps: which Google account is live, when each token runs out, use / remove / rotate, and the live account's quota pools with their reset times — the same figures /antigravity.usage prints. Every change goes through the same code as /antigravity.accounts, so the store and auth.json move together.

Twenty-three commands — prompt, steer, abort, switch models, compact, run a shell command, walk the conversation tree, export — and the answer arrives as the same streaming events the terminal draws. A hook can still ask: the question goes out as a hook_ui_request line and the tool call parks until the host answers it, which is the terminal trick with a different transport.

examples/ask.php is the same stack with no UI at all:

Everything under that line is pig's own: one non-blocking TLS socket, HTTP/1.1 written by hand, SSE parsed as it arrives, coroutines on Fiber. Ctrl-C mid-answer exercises the same abort path the TUI uses.

Built-in Tools

pig ships with four default coding tools matching upstream: read, bash, edit, write. Advanced file search (grep, find, ls) is reachable via --tools:

Web search and documentation reading are provided via the pure PHP extensions/pig-web-search/ extension — web_search (DuckDuckGo), fetch_web_page (the HTML the server sends, as text), browse_web_page and /search <query> — keeping the core agent at its four tools. browse_web_page is the one for pages that are built by JavaScript: it launches the Chrome already installed on the machine in headless mode, speaks the DevTools Protocol to it over pig's own WebSocket client, waits for the page to load, and reads the text out of the live DOM. No Puppeteer, no driver, nothing downloaded — about two hundred lines of PHP, and a machine without Chrome is told so rather than failed three layers down.

MCP servers are read from ~/.pig/agent/mcp.json and <project>/.pig/mcp.json — pi's file, pi's keys — by extensions/pig-mcp/, and each server's tools reach the model as mcp__<server>__<tool>, through the same hooks and permission gate as bash. Stdio and streamable HTTP, ${VAR} and !command in env and headers, /mcp for status and /mcp — a manager in the terminal (tools, reconnect, exposure, enable/disable, sign in), the status elsewhere — and pig mcp add|remove|list|login|logout from the shell. An HTTP server with no Authorization header signs in with OAuth (discovery, dynamic client registration, PKCE, a loopback callback), tokens in ~/.pig/agent/mcp-auth.json and refreshed by the connection; a server whose authorization server has no registration endpoint — GitHub's is one — takes a pre-registered client under "oauth": { "clientId", "clientSecret", "callbackPort" }, and one that advertises the wrong authorization server, or none, takes "authServerMetadataUrl". Credentials are kept per server name and URL, so two servers at one URL can be two accounts; a code whose iss names another authorization server is refused before it is exchanged (RFC 9207); and a server asking for more scope gets a new token that keeps the scope it already had. A server that offers resources brings list_mcp_resources, list_mcp_resource_templates and read_mcp_resource, and what servers log goes to ~/.pig/agent/mcp.log.

codemode, in PHP (extensions/pig-codemode/): with a server at the default exposure the model is shown one tool, codemode, whose description carries the server's tools as PHP signatures, and it writes a script — $tools->mcp__gh__search_code([...]), parallel([...]) for independent calls, ordinary PHP to filter the results, return for what it wants to see. Three slow tools cost one, a sixty-tool server costs a catalog, and a large result costs what the script kept of it. The script runs in a child php -n with disable_functions, open_basedir and a memory_limit between it and the machine; nested calls go through pig's own tools and hooks, so the permission gate holds inside a script too. A server with "exposure": "deferred" has its tools held back until the model asks tool_search for them (BM25 over names, descriptions and schemas), which is how a server with sixty tools costs the context eight. The tool's description is short — the intro, one line per global, and the path of extensions/pig-codemode/CODEMODE.md, which the model reads when it needs a detail — and a script that calls a tool that does not exist is told the close matches.

Requirements

PHP >= 8.3 with ext-json, ext-mbstring, ext-openssl, and ext-pcntl for the terminal UI. stty is the one external binary that is required. fd and rg are needed by the find and grep tools, and pig downloads them into ~/.pig/agent/bin/ on first use if they are not installed (PIG_OFFLINE=1 turns that off).

Fiber arrived in PHP 8.1 and everything rests on it, so 8.1 is the absolute floor. 8.3 is the floor actually declared: 8.1 is end-of-life and 8.2 loses security support at the end of 2026.

No Composer dependencies at runtime, which includes the provider protocols: the HTTP client, the event-stream parser and all five providers are written here. Upstream does none of that — the Anthropic, OpenAI and Google SDKs do it for pi. That is not a preference: PHP has no official SDK for the OpenAI or Gemini APIs at all, and the official Anthropic one streams by iterating a PSR-18 response body synchronously, which would block the single stream_select() that watches the model's socket and the keyboard together — and with it Esc-to-interrupt and typing while the model streams. CLAUDE.md has the full arithmetic, and it is a dated judgement rather than a principle.

Development

The model registry's rows are generated, as upstream's are: scripts/generate-models.php reads models.dev, keeps the models whose protocol is ported, and rewrites the tables in Ai\Models in place — --dry-run prints them instead, and every run reports what was added, removed and changed so a regeneration can be read rather than trusted. Everything around the rows — the base URLs, the two subscription catalogues, the collision rules — is hand-written and untouched.

test/live.php is not part of the suite and never runs by itself: twelve scenarios per provider against the real API, which is the only way to answer whether a provider accepts what pig sends — a replayed thinking signature, a tool result invented for an interrupted call, a conversation carried over from another provider, a prompt past the window. It takes its keys where pig takes its own, so a machine that has signed in needs nothing, and php test/live.php anthropic google names which to run — or php test/live.php google/<model-id> to try one particular model. The id has to be one the registry carries, which is pinned at the upstream anchor commit; a model released since then is declared in ~/.pig/agent/models.json and is then reachable both here and from bin/pig. Each call is capped at a few hundred tokens.

Verify against the floor, not just your PHP: 8.3 rejects 8.4-only syntax at parse time, and it is easy to reach for a feature the declared floor does not have.

PIG_TIMING=1 bin/pig prints what each part of starting up cost, on standard error, before the terminal takes over.

See CLAUDE.md for the porting rules, the decisions on record, and the traps found so far.

Upstream

Ported against pi at commit d0a4c37 (2026-01-02) — the snapshot where agent-loop.ts was 418 lines, before the harness grew. Class, file and method names track upstream so a diff against a newer upstream commit stays mechanical.

License

MIT


All versions of pig with dependencies

PHP Build Version
Package Version
Requires php Version >=8.3
composer-runtime-api Version ^2.0
ext-json Version *
ext-mbstring Version *
ext-openssl Version *
ext-pcntl Version *
ext-pcre Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package pigagent/pig contains the following files

Loading the files please wait ...