Shared public contracts for Ankhorage packages and standalone provider packages.
- Strongly typed app structures
- Serializable schemas for app manifests and UI definitions
- Provider-neutral runtime contracts for auth and database adapters
- Clear contracts between systems without depending on framework internals
- Serializable app, action, theme, infra, and auth config contracts
- UI and navigation definitions
- Auth adapter contracts using signIn, signUp, and signOut naming
- Database adapter contracts for provider-neutral CRUD-style access
- Dedicated subpath exports for focused imports
import type { AppManifest } from '@ankhorage/contracts';
import type { AuthAdapter } from '@ankhorage/contracts/auth';
import type { AnkhCommandProviderManifest, AnkhPackageMetadata } from '@ankhorage/contracts/cli';
import type { DbAdapter } from '@ankhorage/contracts/db';
import type { StorageAdapter } from '@ankhorage/contracts/storage';Contracts keeps theme configuration serializable. Color validation, harmony,
swatch generation, contrast helpers, and semantic color references live in
@ankhorage/color-theory.
import type { ThemeConfig } from '@ankhorage/contracts';
const theme: ThemeConfig = {
id: 'theme-default',
name: 'Default',
light: { primaryColor: '#3366ff', harmony: 'analogous' },
dark: { primaryColor: '#3366ff', harmony: 'analogous' },
};Provider packages can implement the shared contracts without importing runtime, CLI, ZORA, Expo Router, color generation, or app-generation logic.
import type { AuthAdapter } from '@ankhorage/contracts/auth';
export function createSupabaseAuthAdapter(): AuthAdapter {
return {
async signIn(input) {
return {
ok: true,
data: {
accessToken: `token:${input.identifier.value}`,
user: { id: 'user-1', email: input.identifier.value },
},
};
},
async signUp(input) {
return { ok: true, data: { id: 'user-1', email: input.identifier.value } };
},
async signOut() {
return { ok: true };
},
async getSession() {
return { ok: true, data: null };
},
};
}@ankhorage/contracts/cli contains metadata-only discovery contracts for Ankh
packages and command providers.
import type { AnkhCommandProviderManifest, AnkhPackageMetadata } from '@ankhorage/contracts/cli';Provider packages expose package.json.ankh metadata using a package-relative
provider module path:
{
"ankh": {
"category": "infra",
"provider": "./dist/ankh.provider.js",
"capabilities": ["infra.up", "infra.status"]
}
}Metadata-only packages use null for provider:
{
"ankh": {
"category": "contracts",
"provider": null,
"capabilities": ["contracts.cli"]
}
}@ankhorage/contracts now publishes this metadata shape directly from its own
package.json:
{
"ankh": {
"category": "contracts",
"provider": null,
"capabilities": ["contracts.cli"]
}
}Command descriptor paths are relative to the provider category:
category: "infra"withpath: ["up"]maps toankh infra upcategory: "dev"withpath: ["android", "scan"]maps toankh dev android scan
This subpath contains contracts only. It must not depend on commander,
@ankhorage/ankh, provider implementations, or runtime CLI execution logic.
Capability names are dot-separated package metadata identifiers.
Preferred forms:
<category>.<action>for simple capabilities<category>.<resource>.<action>for nested or domain-specific capabilities
Valid examples:
infra.uptemplates.createcontracts.cliboard.web.importdoctor.repo.validatedev.android.rebuildexpoRuntime.plan
Invalid examples:
infrainfra-up.statusinfra.infra..up
AnkhCapabilityId remains intentionally broad at the TypeScript level so
packages can publish stable serializable metadata without embedding policy
validation logic here. Stricter validation belongs later in
@ankhorage/doctor.
Auth providers own identity records. App-facing profile data should be modeled separately, usually in an app table such as profiles.
const auth = {
scope: 'global',
provider: 'supabase',
authorization: { kind: 'RBAC', engine: 'native' },
profile: {
fields: ['email', 'displayName', 'avatarUrl'],
table: 'profiles',
primaryKey: 'authUserId',
createStrategy: 'trigger',
updateStrategy: 'api',
},
};Generated infra can use this metadata to create and maintain app profile rows while leaving identity lifecycle changes to the auth provider.
Contracts separates shared data and runtime contracts from implementation details. Standalone packages such as Supabase, Clerk, database providers, or UI/color packages can depend on these contracts while staying independent from Ankhorage app generation, runtime, CLI, and UI packages.