@manifest-network/manifest-agent-core
v0.23.0
Published
Typed deployment orchestration, recovery, and lifecycle operations for Manifest Network
Readme
@manifest-network/manifest-agent-core
TypeScript orchestration surface for Manifest agent flows. This package owns the deploy / manage-domain / troubleshoot / close-lease orchestration that host surfaces consume in lockstep — a bug fix in the core's recovery branch fixes every host surface simultaneously.
Status. Publicly published on npm as
@manifest-network/manifest-agent-core(ENG-129). Consume vianpm install @manifest-network/manifest-agent-core. The MCP-server adapter that wraps this orchestration surface via elicitation lives at@manifest-network/manifest-mcp-agent.
See ENG-127 for the broader initiative and ENG-128 for the bootstrap PR.
Layering
manifest-mcp-mono — protocol-level tools (RPC over MCP)
manifest-agent-core — orchestration, verification, recovery, plans, journal (this package)
host surface(s) — chat / conversational / autonomous front-endsThe core sits above MCP; host surfaces sit above the core. Callbacks are where surfaces differ — a chat surface emits chat output and AskUserQuestion; a conversational surface updates its UI; an autonomous daemon auto-picks recovery branches per policy.
Public surface
import {
closeLease,
deployApp,
loadChainDenomMap,
manageDomain,
troubleshootDeployment,
} from '@manifest-network/manifest-agent-core';loadChainDenomMap is a helper that pre-loads a chain-registry denom map (the DeployAppOptions.chainDataFile input) for denom humanization — e.g. umfx → MFX — in plan/progress output. Importing the orchestration surface is browser-safe; loadChainDenomMap(path) and deployApp(spec, callbacks, { dataDir }) are opt-in filesystem operations and throw a clear runtime error outside Node.
Each function takes a typed args object plus a callbacks object with onConfirm / onProgress / onComplete / onFailure hooks. deployApp takes an AppDeploySpec; the other three take their own *Args types — only ManageDomainArgs is action-discriminated ({ action: 'set' | 'clear' | 'lookup', ... }), while TroubleshootArgs and CloseLeaseArgs are plain { leaseUuid: string } interfaces. Only deployApp accepts onPlan and onResolveSku (ambiguous-SKU disambiguation) and uses an enriched onFailure — (failure: FailureEnvelope, options: RecoveryOption[]) => Promise<RecoveryChoice> — to drive partial-success recovery: retry the set-domain step, salvage the lease without the custom domain, cancel a pending lease, or close an active one. See RecoveryOptionId in src/types.ts for the exact literal IDs (retry_set_domain, salvage_without_domain, cancel_lease, close_lease). A successful retry_set_domain returns the normal DeployResult; a completed salvage/cancel/close choice terminates the original deploy flow with non-retryable OPERATION_CANCELLED and details.lease_uuid plus the selected details.recovery_outcome, never TX_FAILED. For cancel/close choices, details.stop_outcome and details.lease_state report what stopApp actually observed or did; details.transaction_hash is present exactly when stop_outcome is stopped or cancelled, and absent for already_inactive (including post-broadcast terminal reconciliation). A malformed Fred partial-success envelope that has no usable lease UUID instead fails closed with TX_FAILED, details.partial === true, and an optional bounded details.rejected_lease_uuid; no recovery callback or side effect runs. The other three orchestrators use the simpler (failure: { reason: string }) => Promise<void>. See src/types.ts for the frozen shapes.
DeployAppOptions.fredCompatibility selects the manifest policy: v0.13 (the default),
pr240, or a map such as { 'https://provider.example': 'pr240' }. Unlisted providers
use v0.13. The operation snapshots this configuration before confirmation callbacks;
provider-specific validation runs before creating the paid lease. Initial and edited
previews use the selected provider's policy, including when an edit changes providers.
Plan.manifestValidation reports fred_compatibility, valid, and errors to the
onPlan callback; the rendered plan shows the same policy and validation result before
confirmation. The optional field keeps manually constructed plans compatible. The
library does not read environment variables.
Deployment pricing
deployApp supplies Plan.leaseItems to onPlan: one compute item per service,
followed by one optional storage item. Each PlannedLeaseItem contains its
kind, resolved sku (UUID, provider UUID, name, price, and billingUnit),
quantity, and optional compute serviceName. Plan.leaseItems is required.
The rendered confirmation lists those items and their recurring costs, while create-lease fee simulation uses the same ordered item list. Totals use integer base-unit arithmetic, convert hourly prices to daily when periods differ, and keep different denominations separate. Credit readiness uses those same totals and periods, checks each charged denomination against the 24-hour floor, and warns when any item cannot be priced. Missing prices or unsupported billing units preserve the known subtotal with an explicit unpriced-item count.
Every plan edit repeats resolution, readiness, pricing, and simulation, then
invokes onPlan again with the newly rendered prices. The callback must return
confirm to advance to the intent recap; another edit repeats the loop and
cancel stops it. Cancellation and deadlines remain active while waiting.
Storage resolves by name on the compute provider before confirmation. Missing
or ambiguous storage fails before simulation; onResolveSku handles compute
ambiguity only. Storage lookup errors include details.selection: 'storage'
and details.phase: 'initial' | 'post_edit'. A duplicate storage name on the
compute provider requires another compute provider or a catalog correction.
Malformed storage values fail validation with INVALID_CONFIG. Fred still resolves storage by name at execution, so the plan is
a catalog snapshot, not a storage UUID pin or a price lock. Storage UUID selection
is tracked by ENG-295. The catalog
has no compute/storage category; the selected name does not prove suitability
for persistent storage.
Where each function lives
| Function | Home |
| --- | --- |
| deployApp | src/deploy-app.ts |
| manageDomain | src/manage-domain.ts |
| troubleshootDeployment | src/troubleshoot.ts |
| closeLease | src/close-lease.ts |
SSRF-guarded fetch (Node-only subpath)
The SSRF-guarded fetch factory is re-exported from a Node-only subpath, @manifest-network/manifest-agent-core/guarded-fetch — deliberately kept off the package barrel so browser bundles don't drag in undici / node:async_hooks (mirrors core's @manifest-network/manifest-mcp-core/guarded-fetch split). Import it from that subpath, never the barrel.
Verification failures after mutation
manageDomain set/clear and closeLease preserve their successful core mutation
receipt if later verification fails. Fresh errors retain structured code/message,
original causes and reconciliation details. A receipt containing a transaction
hash adds details.sent: true, preventing whole-orchestration replay through
withRetry; use that hash and lease ID to inspect the chain before another
mutation. already_inactive close outcomes carry no inferred submission evidence.
When a failed blocking teardown converged to terminal state, its optional frozen
details.reconciliation snapshot retains the earlier error non-enumerably and
actual machine diagnostics separately from the later verification cause. After
observed native CheckTx acceptance, inclusion-timeout or lookup failures retain
the validated hash and sent: true, without a transaction code, height or
confirmation. The original failure remains in the SDK cause chain. Explicit
reconciliation.sent: true adds the outer retry veto. Completed cancel/close deploy
recovery preserves the same snapshot. Successful closeLease verification also
forwards it through optional CloseLeaseResult.reconciliation and onComplete;
it is absent when core supplied no snapshot. A failed cancel whose re-query finds
ACTIVE still rejects with TX_FAILED, retaining the earlier attempt under
details.reconciliation. Read-only lookup remains unchanged. See the SDK error contract
for field names, confirmation semantics and submission-evidence limits.
