Source Kinds And Resolved Schemas

Summary

AgentInbox should separate:

The immediate reason is the current remote_source model.

remote_source is a shared runtime host for external sources, but it is not a useful user-facing type on its own. It becomes concrete only after it is bound to a builtin or user-defined implementation module.

This RFC proposes:

Problem

Today the public model mixes two different concepts into one sourceType surface:

This works for simple builtin sources, but it breaks down once user-defined remote implementation modules enter the picture:

As a result, agents do not have a clear way to ask:

Goals

Non-Goals

Boundary With UXC

The recommended split remains:

uxc owns

AgentInbox owns

The important ownership rule is that uxc should stay raw-stream-oriented, while AgentInbox should own the product event model presented to agents.

Terms

Host Type

The runtime class used to host the source.

Examples:

This is primarily an implementation concern used by adapters/runtime routing.

Source Kind

The user-facing concrete source capability.

Examples:

Source kind is what agents should reason about when discovering:

Source Instance

A registered source record identified by sourceId.

This is the concrete object with:

Proposed Model

1. Keep Runtime Host Types Small

The runtime should continue to reason in terms of a small set of host classes.

Today that effectively means:

Builtin sources such as github_repo may remain as compatibility-facing public types in the short term, but the architecture should treat them as resolved source kinds hosted by the shared remote_source runtime.

2. Introduce Resolved Source Kind As A First-Class Discovery Surface

Every source instance should expose a resolved kind identity.

Suggested shape:

{
  "sourceId": "src_xxx",
  "hostType": "remote_source",
  "sourceKind": "github_repo",
  "implementationId": "builtin.github_repo"
}

For a user-defined remote implementation:

{
  "sourceId": "src_xxx",
  "hostType": "remote_source",
  "sourceKind": "remote:acme.my_profile",
  "implementationId": "acme.my_profile"
}

For local_event:

{
  "sourceId": "src_xxx",
  "hostType": "local_event",
  "sourceKind": "local_event",
  "implementationId": "builtin.local_event"
}

Why implementationId

profile is too narrow as a global concept because only remote-hosted sources use that mechanism today, and the loaded object is actually an executable implementation module rather than a declarative profile.

The more general concept is implementation identity:

This keeps the model extensible even if future native source types do not use the remote module contract.

3. Resolved Schema Becomes The Main Agent Discovery Surface

source schema <sourceType> should no longer be the primary way an agent learns how to use a source.

Instead, the main discovery path should be an instance-scoped resolved schema.

Suggested CLI shapes:

agentinbox source schema <sourceId>
agentinbox stream schema preview <sourceKind> [--config-json JSON]

The existing type-level schema can remain as a catalog/overview surface, but it should be clearly secondary.

Resolved Schema Shape

Suggested shape:

{
  "sourceId": "src_xxx",
  "hostType": "remote_source",
  "sourceKind": "github_repo",
  "implementationId": "builtin.github_repo",
  "aliases": ["github_repo"],
  "configSchema": [],
  "eventSchema": {
    "metadataFields": [],
    "eventVariantExamples": []
  },
  "subscriptionSchema": {
    "supportsTrackedResourceRef": true,
    "supportsLifecycleSignals": true,
    "shortcuts": []
  }
}

This is what agents and skills should read before creating subscriptions.

4. Builtin Names Should Behave As Friendly Aliases

Builtin remote-backed kinds such as:

should remain easy public entry points.

But internally they should be treated as aliases over remote hosted implementations.

Examples:

This preserves the easy path without forcing core architecture to keep two separate concepts mixed together forever.

Remote Implementation Contract

For remote-hosted sources, builtin and user-defined implementations should use one contract.

Current remote implementation hooks already include:

This RFC extends that capability model with introspection hooks.

Suggested shape:

interface RemoteSourceModule {
  id: string
  validateConfig(source: SourceStream): void
  buildManagedSourceSpec(source: SourceStream): ManagedSourceSpec
  mapRawEvent(
    rawPayload: Record<string, unknown>,
    source: SourceStream,
  ): MappedRemoteEvent | null

  describeCapabilities?(
    source: SourceStream,
  ): {
    sourceKind?: string
    aliases?: string[]
    configSchema?: SourceSchemaField[]
    metadataFields?: SourceSchemaField[]
    eventVariantExamples?: string[]
  }

  listSubscriptionShortcuts?(
    source: SourceStream,
  ): SubscriptionShortcutSpec[]

  expandSubscriptionShortcut?(
    input: ExpandSubscriptionShortcutInput,
  ): ExpandedSubscriptionInput | null

  deriveTrackedResource?(
    filter: SubscriptionFilter,
    source: SourceStream,
  ): { ref: string } | null

  projectLifecycleSignal?(
    rawPayload: Record<string, unknown>,
    source: SourceStream,
  ): LifecycleSignal | null
}

Not every hook is required immediately.

The important thing is to establish one extensibility surface that:

Remote Runtime Flow

For a remote-hosted source, the intended sync flow is:

  1. resolve the implementation module
  2. validate source config
  3. build the uxc managed source spec
  4. call uxc source.ensure(namespace, source_key, spec)
  5. persist or reuse the managed streamId
  6. call uxc stream.read(streamId, afterOffset)
  7. map each raw_payload through the implementation module
  8. append mapped events into the AgentInbox source event bus
  9. update the consumer cursor

This keeps the provider ingress boundary inside uxc and the agent-facing event model inside AgentInbox.

Subscription Shortcuts

Remote-module-defined subscription shortcuts should be discoverable, but they should not bypass the standard subscription model.

Shortcut expansion should compile down to ordinary fields such as:

This keeps the product model coherent:

Why Not Arbitrary Module-Owned CLI Flags

We should not let each remote module add custom top-level CLI flags like:

That would fragment the product surface and make skills harder to write.

The extensibility point should be structured shortcut discovery, not ad hoc CLI grammar.

User-Defined Remote Modules

User-defined remote modules should remain file-based local extensions in the current design.

The module code should live under:

Today AgentInbox loads them from local disk through config.modulePath.

This RFC does not propose an HTTP API that uploads executable remote module code into AgentInbox.

Why

If remote installation is needed later, it should be designed as a separate module packaging/install story, not as a generic upload-code endpoint.

CLI And API Direction

Primary Discovery

Agents should use instance-scoped schema:

agentinbox source schema <sourceId>

Preview Discovery

Before creating a remote user-defined source, the system should support schema preview:

agentinbox stream schema preview remote:acme.my_profile --config-json '{...}'

or an equivalent shape that resolves the implementation before registration.

Secondary Catalog

Type-level or kind-level schema may remain for:

But it should not be the only source of truth for actual source capability.

Migration Direction

The current model does not need a flag day rewrite.

Suggested migration:

  1. keep existing SourceType compatibility
  2. add resolved fields such as:
    • hostType
    • sourceKind
    • implementationId
  3. add sourceId-scoped resolved schema
  4. move shortcut and lifecycle capability discovery onto the resolved schema
  5. gradually demote bare remote_source from a user-facing primary kind into a lower-level escape hatch

Open Questions