No two factories run the same way. One needs parts synced from its PLM the moment they're released. Another needs torque results from the line's controllers attached to the task that produced them. A third has a rule that only certain grades of material may go into certain assemblies, and it can't depend on someone remembering.
The usual answer is a pile of internal apps and scripts around the MES, each one owned by whoever wrote it. Factorial puts that code inside the system instead, as plugins, and makes them practical to write with the coding agents most engineering teams already use.
What a plugin is
A plugin is a collection of scripts and optional secrets. Scripts are written in Starlark, a familiar subset of Python. Plugins are versioned, go through a configurable approval process before they can be enabled, and are recorded in audit history, so it's always clear which version was enabled and when.
A plugin can contain several kinds of script:
- Hooks run when something happens, like a comment being created or a custom field changing. They run inside the change that triggered them: a hook that calls
fail("...")refuses the change, and nothing it did is saved. - Receivers register an endpoint that accepts
POSTrequests, so another system can send Factorial webhooks. A PLM can post each new part as it's created. - Jobs run on a schedule, from every 15 minutes to every 7 days, to import data, export it, or send reminders.
- Actions are slash commands in the command bar. Each one shows a form for its inputs and runs with the permissions of the person who invoked it.
- Inventory constraints narrow which inventory may be installed against a requirement, and are checked again at the moment of installation.
A hook that notifies quality when a capacitor lot arrives looks like this:
def main(args):
for event in args:
factorial.notifications.create(inputs=[{
"role_ids": [quality_role_id],
"message": "Capacitor lot received, inspect before use.",
"inventory_id": event.subject_id,
}])

Built for agents to write
We don't expect most plugins to be written by hand. We expect them to be written by an engineer working with a coding agent, and we've designed the tooling around that.
The fctl CLI is the same tool for people and agents. An agent can discover what it can do with fctl --help, scaffold a plugin, and upload it:
fctl plugins init
fctl plugins upload ./my-plugin
The API key the CLI uses decides what it can touch. Agents get no special access: the same permissions apply to every request, whoever or whatever is making it.
The parts that make agent-written code trustworthy are the feedback loops:
- A built-in test loop. Every script type can be run by hand with a mocked payload. Its side effects are listed instead of applied, so the agent sees what the script would have done. External requests don't run by default.
- Execution logs. Script runs are logged in the app, so a failure in production can be read and fixed rather than guessed at.
- Context in one paste. Script-writing pages have a Copy Markdown button that bundles the relevant guidance, documentation, existing code, and types into one prompt for an AI conversation. A plugin-writing skill is also available in our open-source skills repository.
An agent that can test its script against a realistic payload, read the side effects, and check the logs is an agent that finds its own mistakes before the floor does.
Screens and queries, too
Not every need is a script. Sometimes it's a screen nobody else needs, or a question no screen anticipated.
- Pages are custom screens, like a station display or a dashboard, built from a single HTML file. Ask an agent for the screen you need and upload what it writes. A page calls Factorial's API as whoever is viewing it, with that person's permissions, so there are no API keys to embed or manage.
- The REST API is complete and built around bulk operations, so an integration can create or update many records in one request.
- Analytics runs read-only SQL over a stable set of views, in the app or through the API. Internal schema changes are absorbed by the views, so a report written today keeps working.
Every change has an accountable person
Automation in a factory raises a fair question: when a script changes a record, who did it?
Factorial records who did something and how: in the app, with an API key, through a plugin, or by Factorial itself. A plugin that runs because Jane completed a task acts for Jane, so its changes are attributed to Jane through that plugin. An organization API key has no person behind it, so its changes are attributed to the key.
Wherever a record says who did something, a small key or plugin icon beside the name marks a change that came through an API key or a plugin. Hover over the name to see the full chain: the person, the key, the plugin, and what triggered it. Programmability doesn't cost traceability.
A system you can program is only useful if you can trust what the programs do. Versioned plugins, a dry-run test loop, logs, and a full actor chain are how Factorial makes that trust practical.
Start with Writing your first plugin, then read the plugin reference.