Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/framework-route-prefix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@agent-native/core": minor
---

Add `runtime.frameworkRoutePrefix` (`AGENT_NATIVE_CONFIG_RUNTIME_FRAMEWORK_ROUTE_PREFIX`) so a deployment can serve framework routes under a public namespace other than `/_agent-native`. Route registration keeps the internal name; the public prefix is translated once at the request boundary, and every URL the framework hands out (client requests, sign-in and OAuth callbacks, magic links, self-dispatch, deploy adapter routing) is built with the configured prefix. Unset, nothing changes.
60 changes: 44 additions & 16 deletions packages/core/docs/content/agent-native-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,23 @@ recommended form.
These are the shared options read from the typed config and the shared
configuration portion of `agent-native.json`:

| Option | Type | Effect |
| ------------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version` | `1` | Optional schema version. If provided, it must be `1`. |
| `onboarding.firstRun` | `"off"`, `"connect"`, `"connect-and-integrations"`, or a mode map | Chooses the first-run Agent Sidebar setup. `off` hides it. `connect` shows Builder/BYOK setup without the generic integrations catalog. `connect-and-integrations` includes that catalog. |
| `runtime.auth.enabled` | `boolean` | Declares whether the app expects the framework or a custom authentication layer. |
| `runtime.database.required` | `boolean` | Declares whether production needs a persistent remote PostgreSQL database. |
| `runtime.environment.required` | `string[]` | Declares additional required environment variable names. Names must match `[A-Za-z_][A-Za-z0-9_]*`; values do not belong in the config. |
| `deployment.environment` | `"local"`, `"beta"`, `"production"`, or `"preview"` | Records the release lane that produced the current client bundle. |
| `deployment.workspace.appsDirectory` | `string` | Relative directory containing app packages for a workspace deploy. Defaults to `apps/`; set `"."` for a workspace whose apps live at its root. |
| `deployment.workspace.authMode` | `"shared"` or `"isolated"` | Controls whether apps mounted by a workspace deploy share auth. Defaults to `"shared"`; `"isolated"` keeps one login per app. |
| `diagnostics.failOnBuild` | `boolean` | When `true`, a production Vite build throws on runtime configuration issues. When absent or `false`, it reports them without failing the build. |
| `instructions.runtime` | `string` | Optional relative Markdown path for the in-app runtime agent. Defaults to `AGENTS.md`. |
| `instructions.development` | `string` | Optional relative Markdown path for development/coding agents. Defaults to `AGENTS.md`. |
| `translations.locales` | `string[]` | Lists the locales the app intentionally ships. `en-US` remains the source locale. |
| `changelog.enabled` | `boolean` | Enables the app changelog workflow and lets agents create user-facing entries. |
| `harness` | `boolean` or `{ runtimes: string[] }` | Enables the hosted tools-only harness, optionally narrowed to `claude-code`, `codex`, `pi`, or `opencode`. See [Harness Agents](/docs/harness-agents). |
| Option | Type | Effect |
| ------------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version` | `1` | Optional schema version. If provided, it must be `1`. |
| `onboarding.firstRun` | `"off"`, `"connect"`, `"connect-and-integrations"`, or a mode map | Chooses the first-run Agent Sidebar setup. `off` hides it. `connect` shows Builder/BYOK setup without the generic integrations catalog. `connect-and-integrations` includes that catalog. |
| `runtime.auth.enabled` | `boolean` | Declares whether the app expects the framework or a custom authentication layer. |
| `runtime.database.required` | `boolean` | Declares whether production needs a persistent remote PostgreSQL database. |
| `runtime.environment.required` | `string[]` | Declares additional required environment variable names. Names must match `[A-Za-z_][A-Za-z0-9_]*`; values do not belong in the config. |
| `runtime.frameworkRoutePrefix` | `string` | The public URL namespace the deployment serves framework routes under. Defaults to `/_agent-native`. One absolute segment of letters, digits, `_`, or `-`; `/api`, `/mcp`, and `/.well-known` are refused. See [Framework route prefix](#framework-route-prefix). |
| `deployment.environment` | `"local"`, `"beta"`, `"production"`, or `"preview"` | Records the release lane that produced the current client bundle. |
| `deployment.workspace.appsDirectory` | `string` | Relative directory containing app packages for a workspace deploy. Defaults to `apps/`; set `"."` for a workspace whose apps live at its root. |
| `deployment.workspace.authMode` | `"shared"` or `"isolated"` | Controls whether apps mounted by a workspace deploy share auth. Defaults to `"shared"`; `"isolated"` keeps one login per app. |
| `diagnostics.failOnBuild` | `boolean` | When `true`, a production Vite build throws on runtime configuration issues. When absent or `false`, it reports them without failing the build. |
| `instructions.runtime` | `string` | Optional relative Markdown path for the in-app runtime agent. Defaults to `AGENTS.md`. |
| `instructions.development` | `string` | Optional relative Markdown path for development/coding agents. Defaults to `AGENTS.md`. |
| `translations.locales` | `string[]` | Lists the locales the app intentionally ships. `en-US` remains the source locale. |
| `changelog.enabled` | `boolean` | Enables the app changelog workflow and lets agents create user-facing entries. |
| `harness` | `boolean` or `{ runtimes: string[] }` | Enables the hosted tools-only harness, optionally narrowed to `claude-code`, `codex`, `pi`, or `opencode`. See [Harness Agents](/docs/harness-agents). |

## Deterministic environment aliases

Expand All @@ -126,6 +127,7 @@ upper snake case and join segments with underscores:
| `runtime.auth.enabled` | `AGENT_NATIVE_CONFIG_RUNTIME_AUTH_ENABLED` |
| `runtime.database.required` | `AGENT_NATIVE_CONFIG_RUNTIME_DATABASE_REQUIRED` |
| `runtime.environment.required` | `AGENT_NATIVE_CONFIG_RUNTIME_ENVIRONMENT_REQUIRED` |
| `runtime.frameworkRoutePrefix` | `AGENT_NATIVE_CONFIG_RUNTIME_FRAMEWORK_ROUTE_PREFIX` |
| `deployment.environment` | `AGENT_NATIVE_CONFIG_DEPLOYMENT_ENVIRONMENT` |
| `deployment.workspace` | `AGENT_NATIVE_CONFIG_DEPLOYMENT_WORKSPACE` |
| `deployment.workspace.appsDirectory` | `AGENT_NATIVE_CONFIG_DEPLOYMENT_WORKSPACE_APPS_DIRECTORY` |
Expand Down Expand Up @@ -414,3 +416,29 @@ see [Environment Variables](/docs/environment-variables). A deployment-level
key is not a substitute for user- or organization-scoped credentials in a
hosted multi-user app. See [Authentication](/docs/authentication) and
[Security](/docs/security) for those boundaries.

## Framework route prefix

The framework serves its own routes — actions, the agent chat stream, events, uploads, authentication — under `/_agent-native`. That namespace keeps framework routes apart from an app's `/api/*` routes and is the default for every deployment.

A gateway or reverse proxy in front of the app may own a different namespace. `runtime.frameworkRoutePrefix` selects the public one:

```ts
import { defineAgentNativeConfig } from "@agent-native/core/config";

export default defineAgentNativeConfig({
runtime: {
frameworkRoutePrefix: "/_platform",
},
});
```

With that setting the browser calls `/_platform/actions/...`, sign-in and OAuth callbacks are issued under `/_platform/...`, background self-dispatch targets `/_platform/...`, and the deploy adapters route `/_platform/*` to the app. Route registration does not change: plugins still mount on `/_agent-native/...`, and the framework translates the public prefix to the internal one once, at the request boundary, before route selection, authentication classification, and the CSRF check. The internal name is not served once a custom prefix is configured; a request to `/_agent-native/...` answers `404`.

The value is resolved once, at `agent-native dev` startup or at deploy build, and written into the browser bundle and the server bundle together. Changing it needs a restart or a new build. The prefix composes with `APP_BASE_PATH`: an app mounted at `/mail` with the prefix `/_platform` serves `/mail/_platform/actions/...`.

A remote installation keeps its own namespace. Requests the framework makes to another Agent-Native app — the MCP hub, the organization directory, A2A peers — are not affected by this deployment's prefix.

Changing the prefix changes URLs registered elsewhere. Before deploying, update OAuth redirect registrations, webhook subscriptions, MCP connection URLs, and external monitors that point at `/_agent-native/...`; magic links and password-reset links issued before the change stop working, and a cached browser bundle must be reloaded.

For a multi-app workspace deploy, set the `AGENT_NATIVE_CONFIG_RUNTIME_FRAMEWORK_ROUTE_PREFIX` alias in the deploy environment so the workspace gateway and every app build read the same value.
3 changes: 2 additions & 1 deletion packages/core/src/a2a/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "../integrations/internal-token.js";
import { readDeployCredentialEnv } from "../server/credential-provider.js";
import { getH3App } from "../server/framework-request-handler.js";
import { publicFrameworkPath } from "../server/framework-route-prefix.js";
import { readBody } from "../server/h3-helpers.js";
import { isSameOriginRequest } from "../server/request-origin.js";
import { generateAgentCard } from "./agent-card.js";
Expand Down Expand Up @@ -348,7 +349,7 @@ export function mountA2A(
return generateAgentCard(
{ ...config, skills },
baseUrl,
`${routePrefix}/a2a`,
publicFrameworkPath(`${routePrefix}/a2a`),
);
}),
);
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/client/agent-chat-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ import {
import { getAnalyticsClientPlatform } from "./analytics-platform.js";
import { getOrCreateAnalyticsSessionId } from "./analytics-session.js";
import { captureError } from "./analytics.js";
import { agentChatStreamingUrl, agentNativePath } from "./api-path.js";
import {
agentChatStreamingUrl,
agentNativePath,
frameworkRoutePrefix,
} from "./api-path.js";
import { getBrowserTabId } from "./browser-tab-id.js";
import { formatChatErrorText, normalizeChatError } from "./error-format.js";
import {
Expand Down Expand Up @@ -2037,7 +2041,7 @@ function runtimeDebugUrlForApiUrl(apiUrl: string): string | null {
if (typeof window === "undefined") return null;
try {
const url = new URL(apiUrl, window.location.href);
const marker = "/_agent-native/";
const marker = `${frameworkRoutePrefix()}/`;
const markerIndex = url.pathname.indexOf(marker);
if (markerIndex < 0) return null;
url.pathname = `${url.pathname.slice(0, markerIndex)}${marker}debug/runtime`;
Expand Down
Loading
Loading