Skip to content

automations: feat: add shared automations protocol - #393

Open
Ulugbek Abdullaev (ulugbekna) wants to merge 8 commits into
microsoft:mainfrom
ulugbekna:ulugbekna/shared-automations
Open

automations: feat: add shared automations protocol#393
Ulugbek Abdullaev (ulugbekna) wants to merge 8 commits into
microsoft:mainfrom
ulugbekna:ulugbekna/shared-automations

Conversation

@ulugbekna

@ulugbekna Ulugbek Abdullaev (ulugbekna) commented Aug 12, 2026

Copy link
Copy Markdown

Summary

Add shared, host-owned Automations to Agent Host Protocol.

The protocol now represents:

  • durable automation definitions and revisions;
  • manual, schedule, and host-defined event triggers;
  • task-level automation runs;
  • run lifecycle, blockers, artifacts, and cancellation;
  • one or more linked ordinary AHP sessions;
  • durable automation/run provenance on created sessions;
  • host capability discovery for creation, schedules, cancellation, preview, and history limits;
  • protocol docblocks and a detailed implementation guide matching the existing
    AHP documentation standard.

This lets multiple AHP clients connected to the same authority share one
definition, scheduler, run claim, and run history instead of independently
scheduling duplicate sessions.

Protocol model

The change introduces two state channels:

ahp-automation:

Owns the durable recipe:

  • title and initial user message;
  • provider, model, custom agent, working directories, and session config;
  • enabled state;
  • trigger collection;
  • revision and next scheduled occurrence;
  • retained run summaries;
  • currently permitted operations.

Definitions use optimistic revisions. updateAutomation.expectedRevision
rejects stale writes rather than overwriting a newer client.

ahp-automation-run:

Owns one task-level invocation:

  • manual or trigger provenance;
  • pending, running, blocked, completed, failed, or cancelled lifecycle;
  • typed blocker reason;
  • ordered session catalog and primary session;
  • artifacts;
  • currently permitted operations.

Runs may contain multiple sessions, supporting retries or workers without
encoding the current one-session local implementation into the protocol.
Ordinary session/chat channels remain authoritative for transcripts, tools,
confirmations, and file changes.

Triggers

Definitions contain a trigger collection:

  • an empty collection is manual-only;
  • portable schedule triggers use one five-field AHP cron expression and an
    IANA time zone;
  • the grammar specifies numeric and named fields, wildcards, ranges, lists,
    steps, and Unix day-of-month/day-of-week matching;
  • seconds, years, macros, and Quartz extensions are intentionally excluded;
  • event triggers use a host-defined type, selected event actions, and open
    schema-defined config.

Hosts describe dynamic event triggers through
listAutomationTriggerDefinitions. This allows a managed authority such as
Mission Control to expose repository events without hard-coding
GitHub-specific trigger enums into AHP.

Capabilities and commands

initialize.automations advertises execution lifetime, creation, schedule
support and an optional minimum interval, cancellation, schedule preview, and
retained history limits.

Execution lifetime describes availability:

  • hostLifetime: scheduling runs while this host process is alive;
  • managed: scheduling continues independently as a managed service.

The change adds:

  • listAutomations;
  • listAutomationTriggerDefinitions;
  • createAutomation;
  • updateAutomation;
  • disposeAutomation;
  • runAutomation;
  • fetchAutomationRuns;
  • previewAutomationSchedule;
  • root automation catalog notifications;
  • definition/run-summary reducer actions;
  • run lifecycle/session/artifact reducer actions;
  • client-dispatchable run cancellation.

runAutomation.requestId is a durable idempotency key, so repeating the same
manual request returns the same run URI.

Capability fields such as create?: {} and runCancellation?: {} are
presence markers. Objects are used instead of booleans so optional detail can
be added later without changing the wire type.

Generated surfaces

The source contract is propagated through:

  • JSON Schema;
  • protocol reference documentation;
  • TypeScript client and state mirrors;
  • Rust client, reducers, and state mirrors;
  • Go client, reducers, and state mirrors;
  • Swift client, reducers, and state mirrors;
  • Kotlin generated types and reducers;
  • reducer fixtures and the round-trip corpus.

The automation state, action, command, capability, notification, run, and
session-provenance types now carry detailed normative docblocks. The expanded
guide covers authority, cron semantics, event discovery, revisions, migration,
run lifecycle, cancellation, retention, multi-client reconciliation, and
security.

The branch is rebased onto current main. Regeneration also incorporates the
current optional BaseParams._meta field into automation command types and
schemas.

Deliberate boundaries

  • AHP shares automations among clients connected to one authority; it does not
    replicate independent hosts.
  • Event types remain authority-defined.
  • Run-history deletion is not part of this protocol revision.
  • Mixed execution profiles inside one authority are not modeled; local and
    managed/cloud execution can be represented by separate authorities.

Validation

  • npm run generate
  • npm test
  • 410 source protocol tests
  • 100% reducer branch coverage
  • Rust workspace and doc tests
  • Go tests
  • 66 TypeScript client tests
  • Swift package build
  • Kotlin generation and tests
  • npm run docs:build
  • change-fragment and release-metadata verification

Companion implementation

A companion draft VS Code PR implements the local Agent Host scheduler,
persistence, transport integration, Agents-window projection, and automatic
migration from the retired renderer-owned automation stores.

Companion VS Code draft PR: microsoft/vscode#330463

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 935e37c8-2b68-40b1-9273-f195cb3af9a0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 935e37c8-2b68-40b1-9273-f195cb3af9a0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 935e37c8-2b68-40b1-9273-f195cb3af9a0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1131c2f6-bcd0-4012-9265-fdb2685179e7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1131c2f6-bcd0-4012-9265-fdb2685179e7
isClientDispatchable did not accept automation or automation-run actions,
so servers could not use it to reject server-only actions arriving on the
new automation channels.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1131c2f6-bcd0-4012-9265-fdb2685179e7
Comment thread types/channels-automation/state.ts Outdated
Comment thread types/channels-automation/state.ts Outdated
Comment thread docs/guide/automations.md Outdated
Comment thread types/channels-automation/state.ts
Collapse recurring schedules to the specified five-field AHP cron format, document the automation and run protocol surfaces, expand the guide, and regenerate every client and schema.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1131c2f6-bcd0-4012-9265-fdb2685179e7
@ulugbekna
Ulugbek Abdullaev (ulugbekna) marked this pull request as ready for review August 12, 2026 19:50
/** Optional host-resolved execution context. */
runtime?: AutomationRuntimeState;
/** Operations currently permitted for this automation. */
operations: AutomationOperation[];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: operations is documented as authoritative and able to change over time, but this channel has no action/reducer path that updates it. A subscribed client can therefore retain stale permissions when run state changes whether update/dispose/run is allowed. Please add an observable replacement action (and consider runtime if it is also live), or define another synchronization mechanism.

Comment thread types/common/messages.ts
'invokeChangesetOperation': { params: InvokeChangesetOperationParams; result: InvokeChangesetOperationResult };
'listAutomations': { params: ListAutomationsParams; result: ListAutomationsResult };
'listAutomationTriggerDefinitions': { params: ListAutomationTriggerDefinitionsParams; result: ListAutomationTriggerDefinitionsResult };
'createAutomation': { params: CreateAutomationParams; result: null };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: An import retry with the same AutomationImportIdentity may resolve to a previously imported automation independently of the newly requested URI, but this command returns null. The caller cannot discover the canonical existing resource in that case. Could createAutomation return the resolved automation URI?

if (action.nextCursor === undefined) {
delete next.runsNextCursor;
} else {
next.runsNextCursor = action.nextCursor;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: automation/runsLoaded does not identify the cursor it consumed, yet it unconditionally replaces runsNextCursor. If requests for C1 and C2 overlap and their broadcast actions arrive out of order, a late C1→C2 page can overwrite C2→C3 and move pagination backwards. Please carry the consumed cursor and advance only on a match, or explicitly require serialized loads.

protocolVersion: shared.protocolVersion,
serverSeq: shared.serverSeq,
defaultDirectory: shared.defaultDirectory,
automations: shared.automations,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: snapshotHandle exposes shared.automations by reference while the API says snapshots should be treated as immutable. readonly automations only prevents replacing the property; a consumer can mutate nested capability fields and thereby alter later snapshots/runtime-owned state. Please clone this small capability graph when constructing the snapshot.

view: { turns: 30 },
});

test('root automation catalogue notifications reach subscriptions', async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: This test is declared inside an already-running async test and its returned promise is not awaited. The parent can finish and cancel/skip these assertions, so the intended notification coverage is unreliable. Please move it to top level (or make it an explicitly awaited subtest).

});

it('inherits request metadata from BaseParams', () => {
it('preserves automation schedule restrictions', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: This replaces the existing BaseParams._meta inheritance regression test rather than adding schedule coverage alongside it. The new automation assertion should not remove unrelated schema-generator coverage; please restore the _meta test as a separate case.

export interface AutomationTriggeredRunCause {
kind: AutomationRunCauseKind.Trigger;
/** Matches the stable {@link AutomationTrigger.id} in the definition. */
triggerId: string;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: Is triggerId alone sufficient immutable provenance after the owning definition is revised? A trigger can be removed or its ID reused with different semantics, leaving historical runs ambiguous. Consider recording the automation definition revision (or an immutable trigger snapshot) in the cause.

Comment thread docs/guide/automations.md
}
```

`requestId` is durable. Retrying with the same automation and request id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review: What retention guarantee does “durable� impose on the (automation, requestId) → run mapping? Run history is explicitly bounded, so if the mapping is pruned with the run, a sufficiently late retry can create a duplicate. Please define whether idempotency survives history pruning and, if not indefinitely, its minimum retention window.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1131c2f6-bcd0-4012-9265-fdb2685179e7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants