Skip to content

feat(run): prepare a Provider from a Program with coral.workspace.createProvider - #2351

Merged
iaptsiauri merged 16 commits into
feat/builtin-provider-immutablefrom
feat/create-provider
Oct 19, 2026
Merged

iaptsiauri merged 16 commits into
feat/builtin-provider-immutablefrom
feat/create-provider

Conversation

@iaptsiauri

@iaptsiauri iaptsiauri commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Stack 3 of 7, on feat/builtin-provider-immutable.

Summary

An Owner's Program calls coral.workspace.createProvider({ namespace, source }). Coral prepares a Provider Setup from the source and returns at once with a Reef link. A person opens it, finishes the Provider in Reef and publishes it. The call does not wait for that person.

 OperationInvoker.invoke
   admit                                  # unchanged: Members and Agents get operation_not_found
+  BuiltinCall::parse                     # namespace, then source: invalid_input, no approval, fetch or Setup
   Disabled -> operation_disabled
-  plan                                   # Built-in Operation: operation_unavailable
+  dispatch: Builtin(call) | Upstream(plan)
   resolve_credentials                    # unchanged: approval_required waits for approval
   fence                                  # unchanged
-  upstream.send
+  Builtin -> perform_builtin             # nothing sent upstream
+    prepare_setup(source)                # as the invoking User, bootstrap destination policy
+    Upstream Outcome:
+      { data: { status: "needs_sign_in", url, namespace }, metadata: { kind: "builtin" } }
+  Upstream -> upstream.send              # unchanged
  • source: openapi_document, openapi_url or mcp_url. A URL must be http or https, with a host and no credentials or fragment.
  • url: {Reef origin}/workspaces/{w}/providers/new?setup={setup id}&namespace={namespace}. Reef's existing Add provider steps resume that Setup with the namespace filled in, for an Owner only. Reef is unchanged.
  • Guidance: "Show the person the returned url. They finish the Provider in Reef. To check whether it is published, search with its namespace as provider." The search filter takes a namespace, or coral.workspace for the Built-in Provider.
  • Failures: invalid_input, outbound_destination_rejected, dispatch_authority_lost. Without a Reef origin, the call fails operation_unavailable. The MCP runtime sets one.
  • HumanInterfaceUrl moves from coral-mcp to coral-run. coral-mcp re-exports it.

Provider Setup expiry now covers Ready Setups:

 settle_deadlines
-  pre-ready Setup past its deadline -> Expired
+  open Setup (pre-ready or Ready) past its deadline -> Expired
 publish / regenerate
-  past the deadline and holding a setup-scoped OAuth secret -> setup_expired
+  past the deadline -> setup_expired

GLOSSARY.md: a Setup expires one hour after it is created, ready or not. A Built-in Operation can return a Reef link that names a Provider Setup. That identity grants nothing; only an Owner can act on the Setup.

Evidence

  • Before: builtin_operation_fails_safely_for_an_owner_and_is_concealed_from_a_member, removed here, asserted that an Owner's createProvider settles operation_unavailable.
    After: crates/coral-run/tests/domain/provider_setup.rs drives real V8 Program Runs:
    • create_provider_returns_the_reef_page_that_finishes_its_setup: for approval_required and enabled. No fetch or Setup before approval. Then one Setup in AwaitingConfiguration, the exact result and link, 1 fetch, 0 upstream sends.
    • invalid_input_fails_before_approval_fetch_or_setup: 8 bad namespaces and sources settle invalid_input. No Approval Request, 0 fetches, no lifecycle event.
    • members_and_agents_cannot_reach_create_provider_and_change_nothing: operation_not_found, lifecycle events unchanged.
    • the_source_fetch_uses_the_bootstrap_destination_policy: the default policy settles outbound_destination_rejected with 0 fetches and no Setup.
  • each_published_builtin_generation_retains_the_coral_defined_catalog (coral-catalog) reads the new result type.
  • Before: a Ready Setup without a secret of its own published after its deadline.
    After: expired_setup_credential_fails_publication_and_creates_no_account and cancellation_and_expiry_leave_no_usable_credential expect ProviderSetupNotReady and an Expired Setup. In regeneration_expires_only_setup_secrets_and_repairs_only_replaced_applications, the row without a secret now fails setup_expired.
  • Gates:
    • make rust-checks (fmt, clippy -D warnings, workspace tests) passed on the top of the stack (feat/builtin-catalog-update, 57525dc; the head since changed only one Reef test fixture): 1344 of 1344 tests, 2 skipped.
    • Not yet run in this repo: make postgres-tests, the Reef gates, the Reel scenarios.

Merge Danger

Door: two-way

No migration and no proto change.

Blast Radius: provider-setup

  • Every Provider Setup now expires one hour after it is created. This includes Reef's Add provider, Refresh operations, Edit configuration and Change account setting. Publication of an older Setup fails.
  • Every Invocation now passes BuiltinCall::parse. Operations sent upstream take the same path as before.
  • Next in the stack, feat/create-provider-self-publish lets createProvider configure and publish the Provider itself.

@iaptsiauri
iaptsiauri added this pull request to stack #2356 October 13, 2026 11:18
@cubic-dev-ai

cubic-dev-ai Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Running ultrareview automatically — this PR appears to change a public API contract, where a missed bug can break the clients and integrations that depend on it, so a deeper multi-pass review is worth running. I'll post findings when complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ultrareview ran automatically — this PR appears to change a public API contract, where a missed bug can break the clients and integrations that depend on it, so a deeper multi-pass review is worth running.

2 issues found across 23 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="GLOSSARY.md">

<violation number="1" location="GLOSSARY.md:232">
P3: `A Reef link one returns` is ungrammatical and obscures which operation supplies the link. Rewrite it as a link returned by `createProvider`.</violation>
</file>

<file name="crates/coral-catalog/src/builtin.rs">

<violation number="1" location="crates/coral-catalog/src/builtin.rs:127">
P3: Add the `coral.admin.createProvider` Program-to-Reef flow to `apps/docs/guides/concepts.mdx`. The page currently omits the returned `needs_sign_in` URL, so users will not learn how to finish the Provider.

(Based on your team's feedback about public behavior documentation.) .</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread crates/coral-catalog/src/builtin.rs
Comment thread crates/coral-provider/src/account/setup_oauth.rs
Comment thread crates/coral-run/src/lib.rs Outdated
Comment thread crates/coral-run/tests/domain/provider_setup.rs
Comment thread crates/coral-run/tests/domain/provider_setup.rs
Comment thread GLOSSARY.md
effective Workspace Owner authority can discover or invoke its Operations; members and Agent Principals cannot. An
Owner can disable and enable it and set its Operation policy, but nobody can rename, reconfigure, or remove it, and it
has no Provider Accounts. Its Operations never return a secret, OAuth URL, or Provider Setup identity to the Program.
has no Provider Accounts. Its Operations never return a secret or an OAuth URL to the Program. A Reef link one returns

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: A Reef link one returns is ungrammatical and obscures which operation supplies the link. Rewrite it as a link returned by createProvider.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At GLOSSARY.md, line 232:

<comment>`A Reef link one returns` is ungrammatical and obscures which operation supplies the link. Rewrite it as a link returned by `createProvider`.</comment>

<file context>
@@ -228,7 +229,8 @@ Operations Coral itself performs, with no upstream dispatch. Its Call Root is `c
 effective Workspace Owner authority can discover or invoke its Operations; members and Agent Principals cannot. An
 Owner can disable and enable it and set its Operation policy, but nobody can rename, reconfigure, or remove it, and it
-has no Provider Accounts. Its Operations never return a secret, OAuth URL, or Provider Setup identity to the Program.
+has no Provider Accounts. Its Operations never return a secret or an OAuth URL to the Program. A Reef link one returns
+may name a Provider Setup; that Setup's identity grants nothing, and only a Workspace Owner can act on the Setup.
 _Avoid_: admin API, administrative calls, coral.admin surface, system provider
</file context>

Comment thread crates/coral-catalog/src/builtin.rs
Comment thread crates/coral-run/tests/domain/support/modules.rs
Comment thread crates/coral-run/tests/domain/provider_setup.rs
…tup expiry branch

RunModule::new and with_adapters now take the ProviderModule that bootstrap
composes, instead of building their own. The MCP runtime gets it from the
gRPC server, as it already does for accounts and the search index.

settle_deadlines expires Ready Setups through the main expiry path, so the
Ready-only scrub after it could no longer run; remove it.

Tests: live_runs() names the test Reef origin, as production does, and the
provider_setup tests build the served-document source in one helper.
@iaptsiauri
iaptsiauri force-pushed the feat/create-provider branch from ba1b736 to d97bc46 Compare October 13, 2026 12:23
@iaptsiauri iaptsiauri changed the title feat(run): prepare a Provider from a Program with coral.admin.createProvider feat(run): prepare a Provider from a Program with coral.workspace.createProvider Oct 16, 2026
@iaptsiauri
iaptsiauri merged commit e7e56fd into main Oct 19, 2026
29 of 36 checks passed
@iaptsiauri
iaptsiauri deleted the feat/create-provider branch October 19, 2026 14:13
simonwhitaker pushed a commit that referenced this pull request Oct 22, 2026
🤖 I have created a release *beep* *boop*
---


## [1.2.0](v1.1.0...v1.2.0)
(2026-10-22)


### Features

* **activity:** record authored source locations for calls and outputs
([#2535](#2535))
([2d735ca](2d735ca))
* **activity:** show persistent Program source beside selected records
([#2569](#2569))
([f403819](f403819))
* add the Claude recipe and read gzipped OpenAPI documents
([#2513](#2513))
([07c27a2](07c27a2))
* **catalog:** share named TypeScript types across a Provider
([#2482](#2482))
([256e37d](256e37d))
* **desktop:** run the runtime on a Postgres database named in
desktop.json ([#2485](#2485))
([96465a0](96465a0))
* **functions:** type coral.providers, coral.workspace and
coral.functions at Saved Function save
([#2526](#2526))
([a465850](a465850))
* **provider:** create the Coral Built-in Provider at coral.workspace in
every new Workspace
([#2349](#2349))
([06e65ca](06e65ca))
* **provider:** store an agent's createProvider request on its Setup
([#2593](#2593))
([92847d2](92847d2))
* **provider:** update every Workspace's Built-in Provider catalog at
boot ([#2355](#2355))
([24615d9](24615d9))
* **reef:** add NextDNS provider recipe
([#2509](#2509))
([e44880e](e44880e))
* **reef:** calmer providers table and a flush app shell
([#2462](#2462))
([ffe279c](ffe279c))
* **reef:** improve the UI on small screens
([#2531](#2531))
([75e020a](75e020a))
* **reef:** make the providers rail vertical tabs with an All providers
entry ([#2552](#2552))
([08d007a](08d007a))
* **reef:** providers page UI tweaks
([#2562](#2562))
([7ca218e](7ca218e))
* **reef:** put the list pages' main action back in the top bar as a
primary button ([#2546](#2546))
([761ea6d](761ea6d))
* **reef:** read ^, $ and * in every filter field
([#2520](#2520))
([d322356](d322356))
* **reef:** refuse a provider display name another provider uses
([#2518](#2518))
([fdcd473](fdcd473))
* **reef:** review provider configuration changes in a dialog
([#2579](#2579))
([24417e9](24417e9))
* **reef:** show search indexing failures on a Provider and its
Operations ([#2504](#2504))
([6cffed0](6cffed0))
* **reef:** show your recent activity summary on the workspace overview
([#2574](#2574))
([0d1dba5](0d1dba5))
* **reef:** title list pages in their toolbar, with the main action
beside it ([#2525](#2525))
([fd44b72](fd44b72))
* **reef:** UI tweaks to provider's page
([#2566](#2566))
([62204ca](62204ca))
* **reef:** unify Activity detail panels and action reviews
([#2544](#2544))
([409d062](409d062))
* return only declared successes from Operation calls
([#2517](#2517))
([0270bf1](0270bf1))
* **run:** enforce the Fan-out Limit inside the Run Owner
([#2571](#2571))
([cb53419](cb53419))
* **run:** introduce the Run Owner for Program requests
([#2524](#2524))
([245d19d](245d19d))
* **run:** let coral.workspace.createProvider configure and publish the
Provider itself
([#2352](#2352))
([088faaf](088faaf))
* **run:** let createProvider configure sign-in and link to Reef's
sign-in step ([#2353](#2353))
([8d5495c](8d5495c))
* **run:** list a workspace's providers with
coral.workspace.listProviders
([#2374](#2374))
([179c43a](179c43a))
* **run:** make the Run Owner survive uncertain commits and lost leases
([#2541](#2541))
([3a1fad1](3a1fad1))
* **run:** name Tasks and Runs with four-word identifiers
([#2558](#2558))
([c82259a](c82259a))
* **run:** prepare a Provider from a Program with
coral.workspace.createProvider
([#2351](#2351))
([e7e56fd](e7e56fd))
* **run:** reshape the Dispatch Fence into one batched check per chunk
commit ([#2550](#2550))
([120c9d3](120c9d3))
* **run:** route approval decisions and cancellation through the Run
Owner ([#2577](#2577))
([77bcbf5](77bcbf5))
* **run:** summarize your recent activity in a Workspace
([#2573](#2573))
([bf4c75e](bf4c75e))
* **search:** show a Saved Function's result fields in its signature
line ([#2522](#2522))
([41365f6](41365f6))
* **search:** trace each reconcile pass and its steps
([#2456](#2456))
([0594094](0594094))
* **ui:** add option to create a correctly-configured Slack app during
Slack provider setup
([#2585](#2585))
([8c3a883](8c3a883))
* **ui:** move Add provider to the providers toolbar
([#2591](#2591))
([e1ee4cb](e1ee4cb))


### Bug Fixes

* **app:** sweep device authorization leases every 15 s
([#2452](#2452))
([1a4e4ae](1a4e4ae))
* **auth:** drop the unverified client name note from the approval page
([#2578](#2578))
([ddf5aa4](ddf5aa4))
* **catalog:** derive each Built-in Operation's contract from the types
Coral parses ([#2582](#2582))
([534e636](534e636))
* **catalog:** import OpenAPI Providers whose Operations request
different OAuth scopes
([#2401](#2401))
([3acfe55](3acfe55))
* **catalog:** keep keyword names in Operation Call Paths
([#2506](#2506))
([b20795b](b20795b))
* **catalog:** never make an Operation unavailable for search material
([#2465](#2465))
([f83c909](f83c909))
* **catalog:** stop rejecting createProvider request headers by name
([#2589](#2589))
([39e54b9](39e54b9))
* **provider:** ask for an OAuth client ID when Coral cannot register
one ([#2580](#2580))
([baefe9e](baefe9e))
* **provider:** bind each Setup to its starter and hide Coral from
Members ([#2480](#2480))
([6011a64](6011a64))
* **reef:** align the catalog table with the first rail entry
([#2484](#2484))
([fb59758](fb59758))
* **reef:** calm the Activity badge and keep it while the stream
reconnects ([#2468](#2468))
([1b66639](1b66639))
* **reef:** frame the providers table again and lower the top bar
([#2472](#2472))
([87e41ee](87e41ee))
* **reef:** pin third-party recipe OpenAPI documents to a commit
([#2510](#2510))
([b4e9280](b4e9280))
* **reef:** replace loose help text with info tips and banners
([#2461](#2461))
([695500a](695500a))
* **reef:** round the page's corners beside the sidebar
([#2503](#2503))
([a1fef64](a1fef64))
* **reef:** shorten OAuth scope chips that share a URL prefix
([#2455](#2455))
([5ae67ec](5ae67ec))
* **reef:** suggest a provider's namespace from its document name, not
its host ([#2565](#2565))
([8d77893](8d77893))
* **run:** name every argument to correct in an invalid_input failure
([#2354](#2354))
([07bd727](07bd727))
* **run:** reject a credential beside createProvider's bearer method and
report unreachable sources as upstream_incomplete
([#2542](#2542))
([590eab7](590eab7))
* **run:** report an MCP JSON-RPC rejection as invalid_input or
upstream_rejected
([#2402](#2402))
([749770b](749770b))
* **search:** load each Generation's schema graph once per search
([#2448](#2448))
([445d945](445d945))
* **search:** retry a failed Saved Function only after one interval
([#2460](#2460))
([a61ab3a](a61ab3a))
* **search:** return no hits for a query without a letter or digit
([#2561](#2561))
([bb0a4f0](bb0a4f0))
* **search:** start the write limit at the lock and build rows before
the write ([#2575](#2575))
([06ad55d](06ad55d))
* **search:** stop a self-referential Promise result from overflowing
the stack ([#2543](#2543))
([1d4f257](1d4f257))
* **search:** stop retrying an index write that fails the same way every
time ([#2548](#2548))
([e3b6d15](e3b6d15))


### Performance Improvements

* **catalog:** dedup credential destinations once per build, not per
Operation ([#2555](#2555))
([0afbcf5](0afbcf5))
* **catalog:** project each named TypeScript type once per Provider
([#2443](#2443))
([153c273](153c273))
* **search:** drop schema text from the phrase test
([#2559](#2559))
([cfdbafa](cfdbafa))
* **search:** index each word of schema text once
([#2547](#2547))
([d1123fb](d1123fb))
* **search:** prepare search entries in the indexer after commit
([#2467](#2467))
([1ab6765](1ab6765))
* **search:** recount only Workspaces whose rows changed
([#2457](#2457))
([777cfb3](777cfb3))
* **search:** skip unchanged rows when an index write runs again
([#2459](#2459))
([43b5188](43b5188))
* **search:** write only the statistics rows that changed
([#2458](#2458))
([8e2832c](8e2832c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: coral-release-bot[bot] <269256696+coral-release-bot[bot]@users.noreply.github.com>
Co-authored-by: release-please[bot] <release-please[bot]@users.noreply.github.com>
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.

1 participant