Repository navigation
How To Call a Capability from Code
The channels call capabilities for you: a page, a form, REST, MCP. Sometimes your own code calls one: a script, a
capability that builds on another, a controller you kept, a job, a test. This page shows each way, and what each one
checks. Since 2.1.0 ($this->capability() 2.21.0).
| From | Call | Who it runs as | Checks, validation, audit |
|---|---|---|---|
| a terminal | php caligrafer.php call get_book id=3 |
full access (--token: a token, --guest: a visitor) |
all three |
| any PHP code | Capabilities::call('get_book', ['id' => 3], $context) |
the context you give | all three |
| a capability | $this->capability('list_books', $input, $context) |
the same person | all three |
| a controller | $this->call('create_book') |
the signed-in person (Context::fromRequest($request, 'web')) |
all three |
| later, in the background | Queue::push('send_loan_receipt', ['loan_id' => $id]) |
the queue's system context | all three, when the worker runs it |
| a test | $this->call('create_book', $input, $this->user(7)) |
the user you give, or 'guest'
|
all three, rolled back after the test |
| PHP, without the checks | Container::make(GetBook::class)->run(['id' => 3]) |
the command line, unless you pass a context | validation only: no access check, no audit |
php caligrafer.php call list_books
php caligrafer.php call get_book id=3
php caligrafer.php call create_book '{"title": "Dawn", "published_year": 1987, "author_id": 2}'
php caligrafer.php call create_book title=Dawn published_year=1987 author_id=2 --guest # as a visitor who is not signed in
php caligrafer.php call create_book title=Dawn published_year=1987 author_id=2 --token cq_... # as a token (or CALIGRAFY_TOKEN=cq_...)It prints the same JSON as REST: {"data": ...} with exit code 0, or {"error": {...}} with exit code 1. Without
--token or --guest it has full access, like any script you run (channel cli in the audit log).
php caligrafer.php capabilities lists what there is to call.
use Caligrafy\Capabilities;
use Caligrafy\Context;
use Caligrafy\ServiceError;
try {
$book = Capabilities::call('get_book', ['id' => 3], Context::cli());
} catch (ServiceError $e) {
echo json_encode($e->toArray());
}Capabilities::call($name, $input, $context, $uploads = null) does what every channel does, in order: finds the
capability, checks the context, keeps, filters and validates the inputs, runs handle(), writes the audit log, and
returns plain data (models become arrays of their columns). Extra input keys are ignored. Choose the context for who
acts (The context): Context::cli() for full access,
Context::system('schedule', 'nightly-report') for work the system does on its own, Context::forToken($row) or
Context::guest() to act as a token or a visitor.
public function handle(array $input, Context $context)
{
$books = $this->capability('list_books', array('author_id' => $input['author_id']), $context);
// ...
}It runs the other capability as the same person, with its checks, its validation and its audit, and throws its
ServiceError. This is how a web-only capability
reuses the work of plain ones.
try { $book = $this->call('create_book'); redirect('/books/' . $book['id']); }
catch (ServiceError $e) { return view('Books/form', ['errors' => $e->fields]); }Without inputs it sends the route variables and the request's parameters (the parameters win on the same name). It runs
as the signed-in person, on the web channel. New code does not need a controller:
Controllers shows how to move one to a declared route.
use Caligrafy\Container;
$book = Container::make(GetBook::class)->run(['id' => 3]);run($input, $context = null) validates the inputs and calls handle(), with Context::cli() when you give none. It
checks no access and writes no audit, and it returns what handle() returns (a model stays a model). Container::make()
builds the class with what its constructor asks for
(Dependency injection).
Reference: Capabilities::call(),
Service::run(),
Controller::call(),
Container::make().
-
A web-only capability from code (G143):
Capabilities::call(),$this->call()andcallanswernot_found; onlyRoute::actionreaches it. -
A job capability anyone may call: the queue runs it with full access, so it checks
$context->actorType()(Background jobs).
-
Testing your app:
$this->call(),$this->action(),assertCapabilityFails() - Background jobs · Scheduled jobs
- Caligrafer:
call
Caligrafy: Describe it. Approve it. Ship it. Your idea turned into a complete app: every feature built once, for web pages, Vue apps, a REST API and AI agents, and online.
Why Caligrafy: the benefits, the measurements, and what it is not yet
-
Quickstart with Claude: describe it, approve it, ship it
or the Quickstart: the same three steps by hand, in 5 minutes
- How Caligrafy works: the ideas in 5 minutes
- Your first capability: build a feature, page included
-
Capabilities in depth
-
#[Capability]: every option - Scheduled jobs: capabilities on a timer
- Notifications: web push and email
- Background jobs: capabilities run later
- Migrations: database changes, in order
- The cache
-
Testing your app
- Dependency injection
- Validation rules
-
Web pages
- Views and page components
- Design styles: another look, one setting
- Declarative routes: every request, in one line
-
Route::page·Route::form·Route::auth·Route::webhook·Route::download·Route::redirect·Route::action·Route::snap· capability routes - How to export a list as CSV
- Controllers: moving one to a declared route · how to, step by step
- Forms and helpers
-
Vue apps
-
Mobile and tablet
-
REST API
-
AI agents
-
Snap Cards and the assistant
- Payments: Stripe and crypto
- Face detection and face login
- OpenAI: chat and images · Assistants
- Open models: Llama, Mistral...
- Chatbots with Watson
- Machine learning in the browser
- Metadata and social cards · search and analytics
-
Putting it online: the production image, the database at every start
-
API reference: every class and method
-
Routing ·
Route·AuthRoutes· pages ·Controller· capabilities -
Data ·
Model·Query· sign-in · jobs ·Notify· payments · AI -
Interfaces · Snap ·
Snap\Cards·Snap\Conversation· testing · tooling · helper functions
-
Routing ·
-
Caligrafer: every command
- Project · build · data · agents · jobs and tests · maintenance · deploy
- Installation, configuration and Caligrafer
- Routing · Request · Controllers · Views
- Vue: flow of information · routes · validations
- Security and upgrading
- Release notes: 2.26 · 2.25 · 2.24 · 2.23 · 2.22 · 2.21 · 2.20 · 2.19 · 2.18 · 2.17 · 2.16 · 2.15 · 2.14 · 2.13 · 2.12 · 2.11 · 2.10 · 2.9 · 2.8 · 2.7 · 2.6 · 2.5 · 2.4 · 2.3 · 2.1 · October 2026 · changelog
- Testing Caligrafy (contributors)