Repository navigation
The JS Client
The JS client is one ES module, with no dependency, that php caligrafer.php client writes from your capabilities:
one async function per capability (create_book becomes createBook), plus call(), capabilities(), configure()
and CapabilityError. Vue apps, the Vite SPA and Node scripts call the capabilities through it, with the session in a
page of the application and a token anywhere else. It talks to Route::capabilities(). Since 2.1.0.
/caligrafy-quill:new-capability create_book books:write: add a book from the Bookshelf Vue app
Claude adds Route::capabilities('/capabilities') to web.php, runs php caligrafer.php client and calls createBook
from the app.
Check before you say OK:
- every call of the app goes through a function of
capabilities.js: noaxios,fetchorAuthorizationheader written by hand for capabilities; -
capabilities.jswas generated again after the last capability change.
-
The route. In
application/config/routing/web.php, beforeRoute::run();:Route::capabilities('/capabilities'); // GET lists, POST /capabilities/{name} calls: the JS client uses it
-
Generate the client.
docker compose exec dev-box php caligrafer.php client public/js/capabilities.jsFor a Vite SPA, write it inpublic/js/capabilities.js written: 17 capabilities, calls /capabilities (Route::capabilities('/capabilities') in web.php) import { createBook, CapabilityError } from './capabilities.js'public/<app>/src/capabilities.js. With another prefix:php caligrafer.php client --prefix /api/capabilitiesforRoute::capabilities('/api/capabilities'). -
Use it in a Vue app.
A Vue app loaded as a library imports it from the page:
import { createBook, listBooks, CapabilityError } from './capabilities.js' try { const book = await createBook({ title: this.title, published_year: this.year, author_id: this.authorId }) this.books = (await listBooks({ author_id: book.author_id })).data } catch (e) { if (e instanceof CapabilityError && e.code === 'invalid') this.errors = e.fields // { published_year: '...' } else throw e }
this.api = await import(env.home + 'public/js/capabilities.js'), thenthis.api.configure({ baseUrl: env.home.replace(/\/$/, '') }). -
From Node, with a personal access token:
import { configure, listBooks } from './capabilities.mjs' configure({ baseUrl: 'http://localhost:8080', token: process.env.CALIGRAFY_TOKEN }) const page = await listBooks({ page: 1 })
- Run
clientagain after you add or change a capability.
| Export | What it does |
|---|---|
one function per capability, createBook(input = {})
|
calls it and returns its result (the data of the answer) |
call(name, input = {}) |
calls any capability by name: POST <prefix>/<name>
|
capabilities() |
what the caller may call, with the input schemas: GET <prefix>
|
configure({ baseUrl, token, prefix, credentials }) |
the application root (default: this origin), a personal access token, the prefix, the fetch credentials (default same-origin) |
CapabilityError |
thrown by a refused call: status, code (invalid, forbidden...), message, fields
|
Each function carries a comment from the capability: its description, its flag (read-only, destructive or writes),
who may call it (public, the scope, or signed in) and its inputs, typed from the schema (number, boolean or
string; optional ones with ?).
In a page of the application it uses the session: the cookie, and the CSRF token it reads once from GET <prefix>
and sends as X-CSRF-Token on every call that is not a GET. No key is ever in the bundle. Elsewhere (Node, another
origin) configure({ token }) sends Authorization: Bearer <token> instead.
Left out of the module: web-only capabilities
and Snap's own capabilities (snap_*).
Reference: Client::generate(),
Route::capabilities().
-
Forgetting
php caligrafer.php clientafter a change: the Vue app calls the old functions. -
A write over the session without
X-CSRF-Token(G54): 403. The client sends it; hand-written calls must too. - A token or a key in a page or a Vue bundle: browser code uses the session; tokens are for programs.
-
The legacy API key in a client page (G27, G50): while
LEGACY_API_KEYis on, client pages get the key. Call capabilities with the JS client and setLEGACY_API_KEY=false.
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)