1. Go to this page and download the library: Download milpa/framework library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
milpa / framework example snippets
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,
return ['expose' => ['plugins.list']]; // → GET /plugins
return ['expose' => ['plugins.list']]; // → GET /plugins
// public/index.php — a custom middleware sits between identity and the handler
$yours = new YourMiddleware(/* … */); // Psr\Http\Server\MiddlewareInterface
$response = IdentityChain::fromContainer($kernel->container())->handle(
$request,
new class ($yours, $handler) implements RequestHandlerInterface {
public function __construct(private readonly MiddlewareInterface $m, private readonly RequestHandlerInterface $next) {}
public function handle(ServerRequestInterface $r): ResponseInterface { return $this->m->process($r, $this->next); }
},
);
// YourMiddleware::process($request, $next) does its work, then $next->handle($request)
use Milpa\Command\Effect\EffectProfile;
new Operation(
name: 'sync.pull',
effects: EffectProfile::readOnly(), // no mutation, no consent, served straight
handler: /* … */,
);
use Milpa\Command\Effect\{EffectProfile, Mutation, Externality, Reversibility, Authority, Subject};
new Operation(
name: 'sync.push',
effects: new EffectProfile(
mutation: Mutation::Persistent, // it writes
externality: Externality::None, // nothing leaves the app
reversibility: Reversibility::Compensatable,
authority: Authority::WriteAsUser,
subject: Subject::Data,
),
handler: /* … */,
);
public function boot(): void
{
// WIRING, not connecting: the class-string is resolved on first get(), not now.
// Its constructor must NOT connect — it reads config and opens on first real query.
$this->container->registerService(\App\Db\Connection::class, \App\Db\Connection::class);
// ANTI-PATTERN — this opens the socket at boot, so `coa list` dies when the DB is down:
// $this->container->registerService(\App\Db\Connection::class, Connection::fromConfig($cfg));
}
$dispatcher->subscribe('operation.executing', function (array $payload): void {
$op = $payload['event']->operation;
if ($op->mutating && $payload['event']->surface === 'http') {
$payload['slot']->stop(); // deny it
// $payload['slot']->shortCircuit($cached); // …or answer for it
}
});
$dispatcher->subscribe('operation.executed', function (array $payload): void {
$e = $payload['event']; // ->result, ->surface, ->ran(), ->shortCircuited, ->stopped, ->error
});
bash
php bin/coa capabilities:enable milpa/ai-gateway --sign
php bin/coa capabilities:enable milpa/agent --sign
export ANTHROPIC_API_KEY=... # or OPENAI_API_KEY
php bin/coa agent "which plugins are on, and would enabling the other one resolve?" --sign
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.