Skip to content

AI agent development quickstart

An AI coding agent can develop a Moltaro workspace without downloading a project or reading product source code. The generated AGENTS.md and CLAUDE.md are intentionally compact bootstrap guides: they identify the workspace, credentials, safety rules, and authoritative sources instead of repeating feature playbooks. Use the full agent-readable documentation for product semantics and examples, the installation’s two OpenAPI documents for exact HTTP contracts, and the server-side C# language service for source work.

Load .moltaro/credentials.env and use MOLTARO_API_KEY as a bearer token. The generated identity has Admin and Configurator access for the authoring operations on this page. Never put the key in source, prompts, logs, or generated output, and never try to create, rotate, or expand the account’s permissions yourself.

Before starting or resuming work, fetch llms-manifest.json, record its ProductVersion and DocumentationVersion, and open the matching detail page from the versioned release notes. Read the summary, detailed changes, migrations, operator actions, and compatibility guidance for that version. Repeat the check when the manifest version or HTTP ETag changes. Release notes explain what changed; the current documentation and the installation-local OpenAPI remain authoritative for supported behavior and exact request shapes.

For hierarchical records, follow the installation-safe discovery, configure, read-back, root/child, filter, and picker sequence in the Parent Tree View developer guide. For an embedded child table on a Form, follow the complete options, read-modify-write-read, YAML, locked-filter, security, and concurrency workflow in the Form Related Table guide; never invent its inverse target or submit a client-owned child filter.

Read WORKSPACE_API_BASE_URL from the downloaded guide. Every route on this page that starts with /api/workspace/ or /openapi/ is relative to that URL, never to https://moltaro.com.

The guide and contracts for the configured installation are:

GET ${WORKSPACE_API_BASE_URL}/openapi/moltaro-public-v1.json
GET ${WORKSPACE_API_BASE_URL}/openapi/moltaro-config-v1.json
GET ${WORKSPACE_API_BASE_URL}/api/workspace/admin/net-operation-project/developer-surface

developer-surface is the machine-readable catalog of supported assemblies, versions, injectable service types, lifetimes, module keys, and .NET reference links. Do not infer support from every public CLR type in a DLL.

The following are Moltaro Application Configuration API endpoints, not Portal endpoints:

GET ${WORKSPACE_API_BASE_URL}/api/workspace/admin/agent-integration
GET ${WORKSPACE_API_BASE_URL}/api/workspace/admin/agent-integration/agents-md
POST ${WORKSPACE_API_BASE_URL}/api/workspace/admin/agent-integration/access-kit

An authenticated agent may call the two read endpoints after the handoff to re-read the installation manifest or generated guide. The access-kit operation belongs to the administrator’s one-time handoff and must not be called by the agent to provision or elevate itself. These routes cannot discover an unknown workspace; the caller must already know WORKSPACE_API_BASE_URL and have permission. The same distinction applies to all /api/workspace/admin/... routes in this guide: they are supported administrative APIs of the configured Application and remain part of the agent development workflow.

Follow the Configuration quickstart to create the entity definition and its fields. Then read it back before writing code:

GET /api/workspace/entity-definitions
GET /api/workspace/entity-definitions/{entityDefinitionId}

Field keys, ids, types, and generated CLR names are data from the installation; never guess them.

Searchability is also explicit installation data. Read the administrative definition’s SearchTargets, SearchMaxPathDepth, and RowVersion, then use the replace-all search-targets operation when the requested solution needs record search. Do not generate legacy full-text flags or a rebuild step. The Entity search contract contains the exact Configuration API and runtime SearchTerm payloads.

When authoring a Reference field through the Configuration API, use the installed OpenAPI enum metadata and choose deletion semantics explicitly: ReferenceDeleteBehavior is 0 None, 1 Cascade, or 2 Restrict. New references default to Restrict. A blocked permanent delete returns HTTP 409 with moltaro.instances.delete.referenced; branch on the stable code rather than its localized message. See Configuration API quickstart. YAML has the same semantics: omission means Restrict for a newly imported Reference or a non-reference field converted to Reference, and preserves the current value when updating a matched Reference; exports contain the effective value.

After any schema change, read the entity again and call the language endpoints again. Every request receives the current server-generated GeneratedWorkspaceContract; completion results captured before a field was added, renamed, or removed are stale.

List templates first because the response states the default folder and which inputs each template requires:

GET /api/workspace/admin/net-operation-project/source-templates
POST /api/workspace/admin/net-operation-project/source-templates/preview

The preview does not create a revision. Entity-bound templates accept a target entity definition id and return source using the current generated CLR type.

4. Explore the generated contract in an unsaved buffer

Section titled “4. Explore the generated contract in an unsaved buffer”

Send the current Content, source Path, and one-based cursor position to:

POST /api/workspace/admin/net-operation-project/source-language/completions
POST /api/workspace/admin/net-operation-project/source-language/hover
POST /api/workspace/admin/net-operation-project/source-language/signature-help

Moltaro automatically adds the current GeneratedWorkspaceContract to every Roslyn snapshot using the same two-project graph, controlled references, language options, and analyzers as Check. Send the CurrentSchemaContractHash from GET .../status as SchemaContractHash on every source-language request. If the schema changes meanwhile, Moltaro returns HTTP 409 with netOperationProject.language.schemaContract.stale; re-read status, schema, and the source buffer before retrying. Hover and signature help also read XML documentation for the supported SDK and active module assemblies. There is no generated-contract download or edit step in the agent workflow.

Before writing module code, inspect developer-surface. For Boards, Entitlement Operations, and Work Schedule, choose the entries with ServiceKind: ApplicationAutomation and Preferred: true:

IBoardAutomationCommandService / IBoardAutomationQueryService
IEntitlementAutomationCommandService / IEntitlementAutomationQueryService
IWorkScheduleAutomationCommandService / IWorkScheduleAutomationQueryService

These services need no manually assembled actor, role set, or Board Data. They run the complete application flow as moltaro-system-automation, retain the original user/function run/correlation in origin metadata, and commit in a separate application scope. Use them only from Action, TriggerHandler, Command, Job, or HttpEndpoint code; Validation and BeforeSaveMutation return moltaro.automation.executionPhase.unsupported. Entitlement commands need a stable business IdempotencyKey. Boards commands deliberately mirror Runtime API behavior without a separate receipt, except Board admission requires a caller-owned UUID OperationKey. Preserve it for an exact retry after an unknown outcome; exact replay returns the original item and changed-payload reuse conflicts. Query the current Board item before starting another logical admission. Returned RowVersion values are concurrency tokens for later mutations.

For Work Schedule, read the Work Schedule C# guide and the generated Work Schedule XML reference. Use a new stable OperationId for each logical command and preserve it only for an exact retry. Calendar writes use the current RowVersion; assignment and exception changes use the last returned ChainVersion. Requests never accept an actor or authority tier. Do not model Operational Location as an exception scope: the supported scopes are Workspace, Site, and Worker.

Inside one explicit function transaction, invoke a Boards command before staging or saving Entity or owned-table mutations. An Entity-first sequence is rejected with moltaroBoards.runtime.entityMutationBeforeBoardCommandUnsupported before the Boards facade opens its separate application scope. Start a new transaction instead of retrying the same ordering.

Boards may have enabled event and status-invariant Constraints. Treat every ordered runtime Errors[] entry as authoritative: branch on Code, retain Target and safe Metadata in diagnostics, and show the workspace-authored Message to the operator without attempting value interpolation. ValidateMoveAsync returns CapturedAtUtc and ordered ConstraintDecisions, but it is only a dry run; execute with the current RowVersion and handle a newly rejected result. Never retry a rejected Constraint as though it were a transient transport failure.

Normal generated-context MoltaroDbContext.SaveChanges[Async] also runs every registered Entity pre-commit provider. A rejection throws MoltaroPreCommitSaveRejectedException; catch it only when the function must shape a controlled domain result, and branch on its ordered Errors[].Code values rather than its message. If function code does not catch it, Moltaro records the run as ValidationFailure, copies the safe provider errors into the run’s validation errors, and sets FailureReasonCode to the stable moltaro.preCommit.rejected. This is a business rejection, not a transient failure. The exact public namespace is Moltaro.Package.NET.ModuleRuntime.Runtime; generated code that catches the exception must include:

using Moltaro.Package.NET.ModuleRuntime.Runtime;

The run-level failure code is deliberately general. One rejected save may contain several provider failures, so code that needs the specific reasons must inspect every ordered Errors[].Code value instead of expecting one exception-level reason code. Inside one explicit transaction, stage every Entity identity in a cross-record unit of work before the first SaveChanges; introducing a new identity in a later save is rejected before lock acquisition. This rule is global to generated-context Entity writes, not conditional on Board usage. Assign all new string ids up front, connect the complete related graph in memory, and issue one SaveChangesAsync. Do not generate sequential-save code merely to obtain a parent’s id. Use the atomic related-graph recipe when generating an import or cross-record command.

POST /api/workspace/admin/net-operation-project/source-language/diagnostics
Content-Type: application/json
{
"RevisionId": "working-revision-id",
"Path": "src/Functions/CloseTicket.cs",
"Content": "// complete current C# buffer",
"SchemaContractHash": "hash returned by GET .../status"
}

Diagnostics compile the supplied buffer together with the other files in the revision. They do not save, build, or activate anything. Each diagnostic has a stable Code, Severity, Origin (Source or GeneratedContract), and a source Path and Range when Roslyn provides a location. Treat any generated contract error as a platform/schema problem; do not rewrite unrelated user source to hide it.

On success, read Limits rather than assuming source-size, timeout, or concurrency values. HTTP 503 with netOperationProject.language.analysis.timeout is terminal for that request: read status and retry from the current revision after the returned bound. If the client cancels, Moltaro safely finishes cleanup in the background without holding the project write lock.

Read GET .../status, then submit BaseRevisionId, BaseSourceChecksum, and file changes to POST .../source-revisions/manual-edit. For an existing file, also send its ExpectedContentHash. A stale revision or checksum returns HTTP 409; a stale file hash does as well. Re-read the source instead of overwriting another change. Successful manual edits return the new revision id, checksum, and effective Limits. HTTP 503 with netOperationProject.source.manualEdit.timeout creates no revision; read status and retry from fresh revision, checksum, and file-hash values.

Read GET .../source-language/source-index?revisionId=... after saving to verify the functions, data sources, services, bindings, keys, and diagnostics Moltaro discovered.

Net Operation Project numeric values are:

KindValueEffect
Build0Compile and automatically activate the successful artifact
Check1Compile only; never activate an artifact

After any schema-affecting change, and before handing off C# business logic, read:

GET /api/workspace/admin/net-operation-project/status

Inspect CurrentSchemaContractHash, IsActiveArtifactSchemaStale, and NeedsValidation, together with ActiveArtifact.SchemaContractHash. These values are independent. A stale active artifact was compiled against an older contract but may still be running. NeedsValidation = false does not prove that the active artifact is current. A successful Check may clear NeedsValidation, but it compiles only and cannot clear the stale-artifact warning. A successful Build activates the replacement; a failed Build preserves the previous active artifact.

When IsActiveArtifactSchemaStale is true, use the exact intended revision from the fresh status, normally WorkingRevision.Id:

  1. Queue Check (Kind: 1), retain its build id, and poll that exact build to terminal Succeeded, Failed, or Cancelled. Inspect the terminal result and diagnostics. Stop without queueing Build unless Check succeeded.
  2. Queue Build (Kind: 0) for the same revision, retain its build id, and poll that exact build to a terminal result.
  3. Read status again and require IsActiveArtifactSchemaStale = false plus a non-empty ActiveArtifact.SchemaContractHash equal to CurrentSchemaContractHash before handoff.

If a matching operation is already queued or running, poll it instead of enqueueing a duplicate. Never select another revision merely because a stale warning exists. If the schema changes again during the sequence, re-read status and restart the decision from the new current contract. The API-first workflow does not download or edit GeneratedWorkspaceContract.

Queue POST .../builds with the saved RevisionId and Kind: 1, then poll GET .../builds/{buildId}. When Check succeeds, queue Kind: 0. A failed Build leaves the previous active artifact running.

Verify the result in GET /api/workspace/admin/function-catalog, then invoke a published command with POST /api/workspace/commands/{functionKey} or enqueue a published job with POST /api/workspace/functions/{functionKey}/enqueue.

Before invoking it, determine the execution model from the installed API: CurrentPublishedContract in the Function Catalog, Source on entity bindings, and Kind in GET /api/workspace/admin/api-functions. For a CRON schedule, join its BusinessFunctionId to the catalog; a valid target is a global Job function, and each due occurrence is queued for a worker. C# async/Task and HTTP 200 do not distinguish blocking from queued work. See Asynchronous operations and polling for the complete decision table and schedule-observation flow.

Do not queue another build merely because one remains queued or running. Poll the returned build id until a terminal status and inspect stored diagnostics on failure. Preserve stable keys across source revisions and reuse a durable idempotency key when retrying the same supported business operation.

Continue with the verified C# recipes for entity events, Boards, Entitlement Operations, and Currency Rates. Read record history through the audit API. Use Reliable API automation for the complete retry, concurrency, polling, recovery, source-limit, and safety rules.

Creating an entity schema is not the completion boundary for a user-facing record type. Configure localized presentation, table/card/form leaf surfaces, Entity List, Details and Drawer hosts, valid selectors, reachable Preview/OpenDetails navigation, menu placement, and least-privilege permissions. Read every configuration back and verify it as both an administrator and an ordinary reader when test identities are available.

Default selectors may validly use SurfaceKey = null and resolve the configured default. CustomKey always requires an existing compatible key. Read the Runtime screens and UI surface library guides for the full product model, then use the installation-local Configuration OpenAPI for exact requests. The generated agent guide routes to these sources and intentionally does not duplicate this feature-specific workflow. The Workspace UI Project is for custom pages and is not a replacement for completing built-in entity surfaces.

Before configuring a table, read its /ui/table-surfaces/configuration/options response and choose FilterItems, SortItems, and DefaultSort from the returned typed targets. Do not guess field paths or infer query behavior from the column renderer. Visible business dimensions that users need to segment or order by—especially statuses and other references—should normally support both operations unless an omission has a recorded rationale.

Reference targets are not interchangeable. A root Status target is distinct from the value displayed to users; Status/Name sorts by its label, while Status/SortOrder is meaningful only when the referenced records actually contain a business order. Use technical paths from the options response and localize only the workspace-authored labels.

Related targets are identified by their complete path. Copy the entire configured Target.Path into runtime conditions; never replace it with ReferencePath, which controls lookup breadcrumb rendering only. See Table filters and sorting and Entity Instance Query.

Read the saved configuration back and verify labels, visibility, VisibleByDefault, item order, typed paths, and DefaultSort. In the Web Application, apply a representative filter and sort and verify totals, every visible row value, and ordering—not merely that the choices appear in a drawer. Then clear the test filter and restore the intended default sort. When possible, repeat the query as an ordinary reader and confirm that inaccessible fields, records, and result counts remain protected by server-side permissions.

When trusted C# needs an outbound credential, first inspect developer-surface for Moltaro.Package.NET.Functions.ISecretService. Inject that service into the function constructor and use its synchronous GetRequired(key) or TryGet(key, out value) methods. Do not invent an async secret API, pass the value in function arguments, or place it in source.

The owner or administrator supplies exact key names and enters values directly through Administration > Secrets or an explicitly authorized write-only API flow. The agent does not need the values: it creates the source revision, runs Check and Build, invokes the intended function flow, reports only a non-secret business marker, and asks the owner to confirm Audit Trail evidence. Provisioning, rotation, external-system changes, rollout, and schedule enablement remain separate owner/operator actions unless the task explicitly authorizes them.

Only an owner or administrator can manage keys through /api/workspace/admin/secrets; Configurator access is not sufficient. An agent must not list, create, rotate, disable, enable, or retire keys unless the user explicitly authorizes that administration work. There is no reveal endpoint.

Trusted C# can resolve every active key it knows. Never log, persist, return, or copy resolved values or derived bearer tokens. Required unavailable values raise stable moltaro.secrets.missing, moltaro.secrets.disabled, or moltaro.secrets.retired codes. One invocation uses one immutable snapshot; after provisioning or rotation, retry with a new invocation rather than looping inside the old one. See the complete Managed secrets guide.

Workspace UI is also API-first:

All routes in this section still use the same WORKSPACE_API_BASE_URL; they are not PublicSite or portal endpoints.

  1. Inspect GET /api/workspace/admin/ui-project/source-templates or the page generators, then apply one to create a revision.
  2. Make subsequent changes with POST .../source-revisions/manual-edit.
  3. Queue Check with POST .../builds and Kind: 0; poll the build.
  4. Queue Build with Kind: 1; it creates an inactive immutable artifact.
  5. Activate it with POST .../artifacts/{artifactId}/activate.

The Workspace UI values deliberately differ from the C# project: Check = 0, Build = 1, and Build does not activate automatically. See the complete Workspace UI Project lifecycle.

GET .../net-operation-project/download produces a ready-to-build ZIP for a human working in a local IDE. It includes the generated workspace contract and matching SDK files. It is transport convenience, not a requirement for an AI agent and not an extra source of truth.