PHPackages                             milpa/framework - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. milpa/framework

ActiveProject[Framework](/categories/framework)

milpa/framework
===============

The composer create-project starting point for a Milpa app: a runtime whose every capability is a declared Operation, reachable from the terminal, from MCP and from a TUI at once. No database, no web framework — an agent-operable substrate you extend with plugins.

v0.1.0(today)00Apache-2.0PHPPHP &gt;=8.3CI passing

Since Jul 31Pushed todayCompare

[ Source](https://github.com/getmilpa/framework)[ Packagist](https://packagist.org/packages/milpa/framework)[ RSS](/packages/milpa-framework/feed)WikiDiscussions main Synced today

READMEChangelog (7)Dependencies (14)Versions (2)Used By (0)

milpa/framework
===============

[](#milpaframework)

The `composer create-project` starting point for a Milpa app: a runtime where **every capability is a declared Operation**, reachable from the terminal, from MCP and from a TUI at once.

No database. No web framework. No command framework. What you get is a substrate an agent can operate, and a plugin system to grow it.

```
composer create-project milpa/framework my-app
cd my-app
php bin/coa
```

What `coa` is
-------------

[](#what-coa-is)

`coa` does not implement any command. It boots the kernel, collects the operations that packages and plugins declared, projects them onto the terminal and runs one:

```
coa — el runtime de esta app. Cada comando es una operación declarada.

Consultan:
  plugins:list  List every installed plugin with its version, type and whether it boots.
  plugins:show  Everything the registry knows about one plugin.
  validate      Valida el manifiesto de un plugin y los proveedores que declara

Cambian algo:
  make             Andamia un artefacto del framework (controller o entity) y lo verifica
  plugins:disable  Turn a plugin off without removing it or its data.
  plugins:enable   Turn a plugin on: it boots from the next request or command.

```

That listing is **derived**, not written. Install a plugin that declares operations and they appear — in `coa`, in the MCP tool registry, and in a TUI — with no edit to any file of this app.

The one idea
------------

[](#the-one-idea)

A capability is declared **once**, as an `Operation`: a name, a description, an input schema, a handler, and whether it mutates.

```
new Operation(
    name: 'backup_create',
    description: 'Take a backup of the data directory',
    handler: [BackupHandler::class, 'create'],
    inputSchema: ['type' => 'object', 'properties' => [
        'label' => ['type' => 'string', 'description' => 'How to name it'],
    ]],
    mutating: true,
    requiresConfirmation: true,
);
```

Return it from a plugin's `operations()` and you are done. A **projector** turns that declaration into each surface's own shape — a command, an MCP tool, a TUI form — and a **renderer** materialises it. Neither of them is something you write.

The corollary is the point: you never write the same capability twice, and you cannot have a capability that the terminal offers and an agent cannot reach.

Consent is part of the declaration
----------------------------------

[](#consent-is-part-of-the-declaration)

`mutating` says the operation changes something. `requiresConfirmation` says the change cannot be undone, and on the terminal that means a **signature over this exact call** — the operation, these arguments, this host:

```
$ coa plugins:remove SomePlugin
This operation mutates and needs your authorization. Re-run with --sign.

  --sign signs THIS call — the operation, these arguments, this host — with your
  key. The authorization cannot be presented for a different target, which is
  what a confirmation flag could never promise.

```

The declaration travels with the operation, so every surface applies the same rule. It is not a flag the terminal invented.

The agent
---------

[](#the-agent)

`milpa/ai-gateway` ships the loop that alternates model ↔ tools. `coa agent` is the line that calls it, and what it hands the model is not a separate catalogue: it is **this app's operations**, the same ones an MCP client sees.

```
export ANTHROPIC_API_KEY=...      # or OPENAI_API_KEY
php bin/coa agent "which plugins are on, and would enabling the other one resolve?"
```

Without a key it says so and stops. There is no demo mode: an agent that answers something plausible without having called anything teaches you to trust answers nobody produced. The answer comes back with how many steps it took and how many tools it had, because "the agent replied" does not distinguish using your app from replying from memory.

It is a **terminal** operation only. An agent running over HTTP with the server's credentials is a different decision, and this template does not take it for you.

Serving operations over HTTP
----------------------------

[](#serving-operations-over-http)

The fourth surface. `config/http.php` names which operations get a route — and it is **empty**:

```
return ['expose' => ['plugins.list']];   //  →  GET /plugins
```

`coa` and MCP run on the machine of whoever invokes them; an HTTP route can be called by anyone who reaches the server. Exposing everything by default would turn installing a plugin into publishing an API nobody decided on. Same doctrine as `config/plugins.php`: what runs is a versioned decision.

An operation that declares `scopes` or `permission` needs someone to decide whether the caller may. **Boot stops** if you expose one without a policy — the error reaches whoever configured it instead of whoever called. Register a `Milpa\Console\Http\OperationHttpPolicy` (`milpa/admin` publishes the one that uses `milpa/auth`) or expose only unprotected operations. All seven `plugins.*` operations declare scopes, so an app with no identity wired can serve `validate` and `make`, not those.

What is opt-in, and why
-----------------------

[](#what-is-opt-in-and-why)

The box is deliberately small. Two examples of what it does **not** include:

- **Filesystem and shell primitives.** A framework that installs an agent with a shell by default is a security decision, not a packaging one. `read`/`write`/`edit`/`grep`/`shell` live in a separate plugin you install on purpose.
- **The remote plugin operations.** `plugins:list`, `:show`, `:enable` and `:disable` are here. `:install`, `:update` and `:remove` appear only once you wire a `PluginInstallerInterface` — an app that never reaches the network does not grow the operations that would.

Layout
------

[](#layout)

```
bin/coa                  the dispatcher — boots, projects, runs
bin/mcp-server.php       the same operations, over MCP
config/plugins.php       which plugins boot (a list you read in a diff)
config/operations.php    which packages contribute operations
config/http.php          which operations get an HTTP route (empty by default)
config/app.php           the config bag plugins read in boot()
public/index.php         the HTTP entry point
src/Plugins/HelloPlugin  proof of life: one route, one response
src/Plugins/OperationsHttpPlugin  serves whatever config/http.php names
src/Operations            this app's own atoms — `agent` lives here

```

`config/plugins.php` is a list, not a scan. What runs in this app is a versioned decision — a plugin that installs itself from the network is an attack surface, not a convenience.

Coming from `milpa/skeleton`
----------------------------

[](#coming-from-milpaskeleton)

`milpa/skeleton` was the previous `composer create-project` target and is now **abandoned** — this package replaces it. Two entry points both saying *start here* is a second source of truth, and the one a newcomer lands on decides what they believe Milpa is.

An app you already created from the skeleton keeps working: what it runs is your code, not that package. If you are starting a new one, start here. What the skeleton brought and this does not are `milpa/auth` and `milpa/data` — add them when your app needs them, which is the point of a floor you build up from. Its one unique capability, the HTTP projection of operations, now lives in `milpa/console` (with the auth-backed policy in `milpa/admin`).

What this is NOT
----------------

[](#what-this-is-not)

It is not a web framework and it will not become one. There is no ORM, no template engine, no router-with-batteries. `milpa/http` ships routing **contracts**; bring your own PSR-7 implementation (this app ships `nyholm/psr7`) and your own persistence.

License
-------

[](#license)

Apache-2.0 © Rodrigo Vicente - TeamX Agency

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 53.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1993784?v=4)[rodrigomx](/maintainers/rodrigomx)[@rodrigomx](https://github.com/rodrigomx)

---

Top Contributors

[![rodrigoteamx](https://avatars.githubusercontent.com/u/269849276?v=4)](https://github.com/rodrigoteamx "rodrigoteamx (8 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (7 commits)")

---

Tags

cliframeworkmcppluginsai-agentsmilpa

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/milpa-framework/health.svg)

```
[![Health](https://phpackages.com/badges/milpa-framework/health.svg)](https://phpackages.com/packages/milpa-framework)
```

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[aimeos/aimeos-typo3

Professional, full-featured and high performance TYPO3 e-commerce extension for online shops and complex B2B projects

1.6k94.1k6](/packages/aimeos-aimeos-typo3)[aimeos/ai-typo3

TYPO3 adapter for Aimeos e-commerce integration

1.0k94.7k2](/packages/aimeos-ai-typo3)[sproutcms/cms

Enterprise content management and framework

242.6k4](/packages/sproutcms-cms)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
