Modules
The intellia modules command group manages the modules registry — bundles
of existing app site and/or workflow roots,
registered as a single catalogue entry. See Modules for the
concept.
Registering a public module — one that enters the catalogue every
organization installs from — is restricted to Hutly’s internal authoring
organization, and to a Hutly superadmin. A module with an intellia- slug is a
first-party module, which must be public and declare a family (see
Naming and the reserved namespace). A
private module is registered by an Admin or Owner of the organization it
belongs to, and is visible and installable only there. list is available to
any organization browsing the catalogue.
Naming and the reserved namespace
Names starting with intellia belong to Intellia’s own modules. Only a
first-party module may create an agent, knowledge base, workflow, schedule or
webhook slug starting with intellia-, or a table name starting with
intellia_. A first-party
module:
- has a slug starting with
intellia-, such asintellia-erp-base; - is
visibility: public; - declares
familyinmodule.yaml(1–16 lowercase letters or digits, starting with a letter), and names every object under it:intellia-<family>-…for slugs andintellia_<family>_…for tables.
Any other module, public or private, names its objects after its own slug, <slug>-… for slugs and
<slug_with_underscores>_… for tables, so a module acme-crm has workflows such
as acme-crm-sync and tables such as acme_crm_lead. intellia modules check
reports an object outside that prefix as an error. Registering the module
returns it as a warning instead and still registers the module, because an
existing workflow’s slug cannot change. An object of any other module whose
name starts with intellia is refused.
When you name an agent, knowledge base, schedule, webhook or workflow
“Intellia …” without giving it a slug, the platform derives a slug with its
kind in front, such as agent-intellia-helper or workflow-intellia-sync. A
slug or table name you type yourself in the reserved space is refused.
Each module owns the reserved objects it installs, and neither a deploy nor an activation takes over another module’s object. A first-party deploy adopts a reserved object this module installed or one no module installed. Activation adopts only the reserved objects this module installed, plus a dependency’s table, which it adopts as it stands.
| Error | Meaning |
|---|---|
reserved_namespace |
A slug or table name you supplied is in the reserved space, and its detail field says which name to change; or a module slug starts with intellia- but the module is not public. |
module_object_taken |
A reserved object of that name already belongs to another module, or to this organization (owner names it). |
module_namespace_violation |
A first-party module has objects outside intellia-<family>- / intellia_<family>_, or another module has objects starting with intellia (names lists them). |
module_family_required |
A first-party module has no family in module.yaml. |
module_dependency_missing |
A dependency kept from the module’s last registration is no longer registered. Remove it from dependsOn; write dependsOn: [] to clear the stored edges, since an absent key keeps the last registration’s edges. |
module_bundle_unresolved |
A first-party module’s closure, or the closure of a dependency (reason names it), could not be assembled, so nothing was registered. |
module_deploy_header_invalid |
The first-party deploy claim names a slug outside the reserved space, or came from a sandbox token. |
intellia modules define
Register a module. Its version goes up only when its content changed since the
last registration. Every --root must reference an app site or
workflow that already exists in the org, and carries its own required
description.
intellia modules define \
--slug acme-portal \
--name "Acme Portal" \
--description "Bundles the Acme storefront site with its nightly sync workflow." \
--root "app_site:3f9e2b3a-2222-4c11-9b8e-111111111111:the storefront" \
--root "workflow:7c1d44f0-3333-4d22-8c9f-222222222222:nightly sync"
intellia modules define \
--slug acme-portal \
--name "Acme Portal" \
--description "Bundles the Acme storefront site with its nightly sync workflow." \
--visibility private \
--category "e-commerce" \
--tags "portal,acme" \
--root "app_site:3f9e2b3a-2222-4c11-9b8e-111111111111:the storefront" \
--pretty| Option | Description |
|---|---|
--slug <slug> |
Module slug, unique in the public catalogue and within your org (required) |
--name <name> |
Module display name (required) |
--description <description> |
Module description (required) |
--visibility <visibility> |
public or private; omit to keep the stored value (a new module is private). public requires Hutly’s internal authoring org and a Hutly superadmin; an intellia- slug requires public |
--category <category> |
Optional category |
--tags <csv> |
Comma-separated tags |
--root <spec> |
Root as <kind>:<resourceId>:<description> — kind is app_site or workflow (repeatable) |
--pretty |
Pretty-print JSON output |
intellia modules get
Fetch a single module by id, including its roots.
intellia modules get 3f9e2b3a-2222-4c11-9b8e-111111111111
intellia modules get 3f9e2b3a-2222-4c11-9b8e-111111111111 --pretty| Option | Description |
|---|---|
--pretty |
Pretty-print JSON output |
intellia modules list
List the platform-wide public catalogue — every public module, regardless
of which organization authored it — plus your own organization’s modules if
it’s an authoring organization (including any private ones it owns).
intellia modules list
intellia modules list --pretty| Option | Description |
|---|---|
--pretty |
Pretty-print JSON output |
intellia modules project
Project a registered module’s source into a portable, reviewable YAML tree on
disk — everything the module bundles (app sites, apps, workflows, tables,
agents, knowledge bases), rewritten as !ref-linked files under --out. This
does not deploy, activate, or install anything; it only writes the tree so it
can be reviewed, diffed, or checked into version control. Deploying a
projected tree back into an organization is a later capability.
When the module has a captured source bundle (see deploy below), project
unpacks that bundle directly instead of re-projecting from live records — the
authored tree (comments, structure, anything the DB projection can’t
recover) wins, and a drift warning prints if a workflow or table in the
module was edited after the capture. Projection from live records is the
fallback, used only when no bundle exists (a module predating source
capture). Pass --projected to force live-record projection regardless of a
captured bundle.
intellia modules project 3f9e2b3a-2222-4c11-9b8e-111111111111 --out ./acme-portal
intellia modules project 3f9e2b3a-2222-4c11-9b8e-111111111111 --out ./acme-portal --projected| Option | Description |
|---|---|
--out <dir> |
Output directory for the projected source tree (required) |
--projected |
Skip the captured source bundle and always project from live records |
--pretty |
Pretty-print JSON output |
When falling back to live-record projection, the emitted tree follows a fixed layout:
acme-portal/
module.yaml # module metadata, dependsOn, and roots, each a !ref
app-sites/<slug>.yaml # one file per app_site root: its own site, or attachTo a dependency's site
apps/<app-slug>/
manifest.yaml # the app's manifest, refs rewritten to !ref
<artifact filename> # the app's artifact bytes
workflows/ # every workflow the module's roots pull in
tables/ # shared tables referenced by those workflows
agents/ # shared agents referenced by those workflows
knowledge-bases/ # shared knowledge bases referenced by those workflows
functions/ # inline function code from those workflows (if any)
scripts/ # inline bash-step code from those workflows (if any)App artifact bytes are not returned inline by the API — the module’s source
bundle carries a presigned S3 URL per artifact, and the CLI downloads the
bytes directly from S3 into apps/<app-slug>/<filename>.
A projected tree holds only the module’s own resources. When one of its pages calls a workflow that a module it depends on installs, the page’s manifest names that workflow by its slug and the module, instead of pointing at a file:
workflows:
- !ref ../../workflows/post-entry.yaml
- slug: get-my-roles
module: erp-baseDeploy needs no copy of the dependency’s tree for this. It checks that the
module is in dependsOn, that it is registered in the organisation, and that
it installed a workflow with that slug, and stops before writing anything
when one of those does not hold. A !ref into a dependency’s own tree beside
this one still works.
intellia modules deploy
Deploy a projected module tree (the layout project emits) into the
configured organization and register it. This is the code/CI authoring
channel — the transport the deploy-modules CI action uses to publish
curated modules committed under modules/ into Hutly’s internal authoring
org. It is not required for every module; a module authored interactively (via
Sammy) is registered directly with define.
intellia modules deploy ./acme-portal
intellia modules deploy ./acme-portal --prettyDeploy walks the tree in dependency order:
- Site checks — before anything is written, deploy reads every app site
the tree declares and refuses the whole deploy when the site belongs to
another module, when a declared path already holds a page another module
registered or an unregistered page whose content differs from the tree, or
when an
attachTosite’s owner has not recorded its page paths. - Workflow closure — every workflow the tree contains (the module’s own workflow roots plus any workflow an app manifest references), reusing the standard workflow deploy so tables, agents, and knowledge bases the workflows pull in are deployed and the state machines published. A manifest workflow that belongs to another module’s tree is not deployed here; that module deploys it.
- App sites and apps — for each app_site, its artifact is published, its
embedded manifest approved (the server resolves the manifest’s workflow
slugs to the ids just deployed), and each app attached at its path. An
attachTofile adds its apps to the named dependency module’s site, which must already be deployed, and never renames or reconfigures that site. A re-deploy that changes nothing keeps the registry version with any CLI, since the version ignores artifact version ids. From CLI 1.11.1, a page whose built file matches the artifact version it already serves also keeps that version instead of appending an identical one. - Registry — the module is registered with its roots resolved to the ids
deployed above, in
module.yamlorder. Deploy then checks that the platform recorded the page paths it sent, and stops withModule "<module>" registered, but the platform did not record its app page paths, …when the platform is older than the CLI. Registering also gives the authoring org the starter rows a table’sseed:declares, the rows a consumer org gets at activation, and like activation it writes them only into a table that is still empty. A table that could not be seeded comes back as a warning naming it.
Deploy is idempotent by natural key: workflows match by slug, tables by
name, agents and knowledge bases by slug, app_sites by slug, apps by path. A
re-deploy removes a page its tree no longer has only when this module
registered that page on its last deploy, or, on a site the module owns but has
no record of yet, when no other module registered it. Pages another module
added to the same site stay. The module upserts by its organization and slug.
The committed tree stays id-free — a re-run against the same org updates every
resource in place and produces no duplicates. A tree that declares
visibility: public in its module.yaml can only be deployed into Hutly’s
internal authoring org. Each app site goes in one file; a tree that declares
the same site in two files stops at load.
These refusals stop the deploy before anything is written:
| Message | What to do |
|---|---|
App site "<site>" is owned by module "<module>"; choose another site slug |
Give this module’s site its own slug. |
Page "<path>" on app site "<label>" belongs to another module; choose a different path |
Move this module’s page to a free path. |
Module "<module>" is not registered in this organisation; deploy "<module>" first |
Deploy the module you attach to, then this one. |
App site "<site>" is not owned by module "<module>"; attach to a site "<module>" owns |
Name a site the dependency owns in attachTo. |
App site "<site>" of module "<module>" has no recorded page paths; deploy "<module>" with CLI 1.10.0 or newer first |
Re-deploy the owner with this CLI. |
Deploy the owner of a site that other modules attach to with CLI 1.10.0 or
newer. An older CLI sends no page paths, so register refuses it with
module_attach_owner_paths_required, and before that refusal it has already
removed every page on the site that is not in its own tree, other modules'
pages included.
If a deploy fails after it wrote pages, for example on a dropped
connection, run the same deploy again without changing the tree. A page at one
of the module’s paths that no module has registered is taken as the module’s
own only when it holds exactly the content the tree would publish there, which
is what the failed deploy left. Deploy then updates it in place, on the
module’s own site and on a site it attaches to alike. Any other unregistered
page at that path, such as one a person made by hand, stops the deploy before
anything is written, with
Page "<path>" on app site "<label>" exists but was not registered by any module and its content differs from this tree; remove it, or register it with its owner, then deploy again.
If you changed the tree after the failed deploy, remove the pages it left and
deploy again.
A first-party tree declares its family next to its visibility:
slug: intellia-erp-base
visibility: public
family: erpA bridge joins two optional modules, for example stock and sales. It
declares both in dependsOn and sets bridge: true in module.yaml. The
in-app catalogue leaves a bridge out; the in-app installer adds it to an
install plan once every module it depends on is installed or being installed
(an older installed version is upgraded alongside), so it arrives with
whichever of them comes last.
Omitting bridge keeps the stored value.
define has no --family option, so a first-party module is first registered
with deploy; a later define keeps the stored family. Before writing
anything, deploy stops a tree whose slug, visibility and family do not agree
(see Naming and the reserved namespace).
After deploying, modules deploy captures the deployed directory as a source
bundle — registered against the module, every app_site it deployed, and every
artifact version it published — so intellia source list <kind> <id> /
intellia source pull <kind> <id> -o <dir> can recover the exact authored tree
later. Capture defaults to the nearest ancestor directory holding
module.yaml or .intelliarc.yaml; use --source-root to capture a different
directory instead. A module whose workflow TypeScript imports files from
outside its own directory — a shared contracts/ folder in a repo of several
modules — must deploy with --source-root <repo root>, or the captured
bundle omits those files and source pull cannot rebuild the workflows.
| Option | Description |
|---|---|
--source-root <path> |
Directory to capture as the source bundle (default: nearest module.yaml/.intelliarc.yaml ancestor) |
--pretty |
Pretty-print JSON output |
intellia modules activation (step-by-step)
Drive a module activation session one step at a time. This is the
underlying machine intellia modules activate
walks automatically; use the activation subcommands directly when a hole
needs interactive resolution (a missing secret or integration) between
begin and deploy. See Modules for the concept.
intellia modules activation begin <moduleId>
Begin an activation session for a registry module. <moduleId> is a module
id from the catalogue (intellia modules list). Prints { sessionId, preview },
where preview carries the module summary, any unresolved holes
(secrets/integrations), and the derivedSlug (empty for workflow-only
modules).
intellia modules activation begin 3f9e2b3a-2222-4c11-9b8e-111111111111intellia modules activation get <sessionId>
Print an activation session’s current state, including its step
(preview → holes → configure → accepted → deploying →
done/failed).
intellia modules activation get 7c1d44f0-3333-4d22-8c9f-222222222222intellia modules activation holes <sessionId>
Recompute and print the session’s unresolved holes (secrets/integrations still required before the session can be accepted).
intellia modules activation holes 7c1d44f0-3333-4d22-8c9f-222222222222intellia modules activation configure <sessionId>
Set the activated module’s app_site slug and any params. Omit --slug for a
workflow-only module (no app_site to slug).
intellia modules activation configure 7c1d44f0-3333-4d22-8c9f-222222222222 \
--slug acme-portal \
--params '{"region":"au"}'| Option | Description |
|---|---|
--slug <slug> |
app_site slug for the activated module (optional; provide it for modules that carry an app_site) |
--params <json> |
JSON-encoded params object |
intellia modules activation accept <sessionId>
Accept the session. This is a strict gate — it rejects (409,
activation_holes_unresolved) if any holes remain unresolved.
On success the session advances to accepted.
intellia modules activation accept 7c1d44f0-3333-4d22-8c9f-222222222222intellia modules activation deploy <sessionId>
Start the async clone of the module’s resources into the org. The session
moves to deploying, then done or failed as the worker progresses; poll
with activation get to watch it land.
intellia modules activation deploy 7c1d44f0-3333-4d22-8c9f-222222222222intellia modules activate
One-shot activation walker: begin → (holes gate) → configure →
accept → deploy → poll until the session reaches done or failed.
<target> is either:
- a registry moduleId — the standard catalogue path, or
- an existing directory — an uploaded-origin module tree (the layout
intellia modules projectemits, typically after Sammy has edited it). Uploaded origin currently supports workflows and agents only; a tree that also bundles tables, knowledge bases, or app_site apps fails loud rather than activating a partial module.
If the session has unresolved holes, the command stops and prints the
activation subcommands needed to resolve them and continue manually — a
one-shot activation cannot resolve holes interactively.
intellia modules activate 3f9e2b3a-2222-4c11-9b8e-111111111111
intellia modules activate ./acme-portal| Option | Description |
|---|---|
--pretty |
Pretty-print JSON output |
Activating over existing tables
When a module’s table already exists in the organisation, activation compares
the two schemas. Identical tables are adopted as they are. If the module’s
version adds to the table — a new column, index, unique constraint or foreign
key, a default, a description, or a required flag being dropped — activation
applies those changes and reports each one in the activation’s warnings, for
example: Table "stock_ledger" was updated to the module's schema: Add column "qty".
Activation never removes anything. Columns, unique constraints and indexes on the organisation’s table that the module does not declare are left in place, so a customer’s own columns survive re-activation, and a module version that no longer declares a column leaves that column and its values where they are.
What activation does not apply is a tightening of something the module declares: making a column required, changing which table a column links to, or dropping a foreign key the organisation added to a column the module declares without one. The activation fails once, names every such step, and does not retry:
Cannot activate: table "stock_ledger" in this organisation needs changes that
activation does not make on its own — Make "qty" required. Apply them with
`intellia tables push` or remove the table, then re-activate.
Two other conflicts fail once the same way, with the server’s reason after the table name, and do not retry: a column whose type or Data Dictionary link differs from the module’s, and a unique constraint, foreign key or required new column that the table’s existing rows violate:
Cannot activate: table "stock_ledger" in this organisation — Cannot add a
unique constraint on (sku): 3 duplicate group(s) exist. Remove the
duplicates first.
intellia modules check reports the same
judgement from the declarations alone before anything is deployed, and names
what a dependent module leaves in place, for example leaves in place: column "legacy".
intellia modules hide <moduleId> / intellia modules unhide <moduleId>
Toggle an activated module’s visibility for the org, without deactivating
it. hide moves it to the hidden state; unhide moves it back to
active.
intellia modules hide 3f9e2b3a-2222-4c11-9b8e-111111111111
intellia modules unhide 3f9e2b3a-2222-4c11-9b8e-111111111111| Option | Description |
|---|---|
--pretty |
Pretty-print JSON output |