Skip to content
Open
8 changes: 5 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ChittyCommand is a unified life management and action dashboard for the ChittyOS
**Repo:** `CHITTYOS/chittycommand`
**Deploy:** Cloudflare Workers at `command.chitty.cc`
**Stack:** Hono TypeScript, React + Tailwind, Neon PostgreSQL (via Hyperdrive), Cloudflare R2/KV
**Canonical URI:** `chittycanon://core/services/chittycommand` | Tier 5
**Canonical URI:** `chittycanon://core/services/chittycommand` | Tier 2 (Platform) with Tier-5 dashboard surface

## Common Commands

Expand All @@ -29,7 +29,7 @@ wrangler secret put DATABASE_URL

## Architecture

Single Cloudflare Worker (`chittycommand`) serving API + cron. Frontend is a separate React SPA at `app.command.chitty.cc` (Cloudflare Pages).
Cloudflare Worker (`chittycommand`) serves the API, ActionAgent, MCP, and request-side meta-orchestrator surfaces; a supervised persistent daemon consumes the same Goal → Plan → Intent and executor registry for durable dispatch. Frontend is a separate React SPA at `app.command.chitty.cc` (Cloudflare Pages).

### Data Sources

Expand Down Expand Up @@ -76,7 +76,9 @@ Three modes:
- `src/lib/validators.ts` — Zod schemas for request validation
- `src/routes/bridge.ts` — Inter-service bridge (scrape, ledger, finance, Plaid)
- `src/routes/mcp.ts` — MCP server for Codex integration (28 tools)
- `src/routes/meta.ts` — Public canon/schema/beacon + authenticated whoami
- `src/routes/meta.ts` — Public canon/schema/beacon + authenticated whoami/intent execution
- `meta/intent.ts` — Goal → Plan → Intent lifecycle
- `meta/executors/` — Canonical executor registry; includes read-only `legal_matter_bootstrap` projection to ChittyCounsel
- `src/routes/connect.ts` — ChittyConnect discovery proxy (rate-limited)
- `src/routes/ledger.ts` — ChittyLedger evidence/custody passthrough
- `src/routes/context.ts` — Persona/context management (user + global)
Expand Down
2 changes: 2 additions & 0 deletions CHARTER.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Provide a unified life management and action dashboard that ingests data from 15
| Upstream | ChittyScrape | Browser-based scraping for portals without APIs |
| Upstream | ChittyLedger | Evidence and document ledger sync |
| Upstream | ChittyEvidence | Evidence facts, documents, entities for case timelines |
| Upstream | ChittyCounsel | Read-only legal matter bootstrap, case-strategy retrieval, and governed counsel work-product projection |
| Upstream | ChittyConnect | Inter-service connectivity and discovery; **forever-context** read/write via ContextConsciousness + MemoryCloude; **sensitive-intent secret brokerage** path for all credential access (no inline secrets) |
| Upstream | ChittyRouter | Unified ingestion gateway (scrape, email routing) |
| Upstream | ChittySchema | Canonical schema validation and drift detection |
Expand Down Expand Up @@ -155,6 +156,7 @@ Executors self-register at module load (side-effect imports from `meta/executors
| `intent_type` | Canonical URI | Notes |
|---------------|---------------|-------|
| `update_obligation_status` | `chittycanon://core/services/chittycommand/executors/update_obligation_status` | Real Neon write to `cc_obligations`. Source: `meta/executors/update-obligation-status.ts` |
| `legal_matter_bootstrap` | `chittycanon://core/services/chittycommand/executors/legal_matter_bootstrap` | Read-only ChittyCounsel bootstrap projection. Requires `privileged` + `legalink`; writes no evidence or facts. Source: `meta/executors/legal-matter-bootstrap.ts` |

> **Future executors** (e.g. `mercury_payment` — 🔒 REAL-MONEY, will require fresh `autonomous` sovereignty assessment and an enforced USD 500 per-intent cap) are tracked in ADR-001 but are NOT yet registered in `meta/executors/index.ts`. They will be added in follow-up PRs and listed here at the same time the executor file is committed. This table is the authoritative list of currently-registered executors — do not document executors that do not exist.

Expand Down
4 changes: 2 additions & 2 deletions CHITTY.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ Source: `chittycanon://gov/governance#three-aspects`

### Ecosystem Position

- **Upstream**: ChittyAuth, ChittyTrust, ChittyID, ChittyConnect (ContextConsciousness + MemoryCloude + sensitive-intent secret brokerage), chittyagent-orchestrator (routing + channel fanout), chittyagent-tasks (queue + lease pattern), chittyagent-ch1tty (MCP portal/OAuth), ChittyFinance, ChittyBooks, ChittyAssets, ChittyCharge, ChittyScrape, ChittyLedger, ChittyEvidence, ChittyRouter, ChittySchema, ChittyCert, ChittyRegister, ChittyChat.
- **Downstream / sub-channels**: ChittyServ cluster nodes (`chittymini-01..06`, `chittyserv-vm`) — each runs a supervised `daemon/` process and registers as an L-type sub-channel via `agent.chitty.cc/api/v1/channels`. ActionAgent (chat surface) and dashboard SPA at `app.command.chitty.cc` are sibling consumers of the same `meta/executors/*` registry.
- **Upstream**: ChittyAuth, ChittyTrust, ChittyID, ChittyConnect (ContextConsciousness + MemoryCloude + sensitive-intent secret brokerage), chittyagent-orchestrator (routing + channel fanout), chittyagent-tasks (queue + lease pattern), chittyagent-ch1tty (MCP portal/OAuth), ChittyFinance, ChittyBooks, ChittyAssets, ChittyCharge, ChittyScrape, ChittyLedger, ChittyEvidence, ChittyCounsel, ChittyRouter, ChittySchema, ChittyCert, ChittyRegister, ChittyChat.
- **Downstream / sub-channels**: ChittyServ cluster nodes (`chittymini-01..06`, `chittyserv-vm`) — each runs a supervised `daemon/` process and registers as an L-type sub-channel via `agent.chitty.cc/api/v1/channels`. ActionAgent (chat surface) and dashboard SPA at `app.command.chitty.cc` are sibling consumers of the same `meta/executors/*` registry. Legal matter bootstrap is projected through the registered `legal_matter_bootstrap` executor and reads ChittyCounsel without mutating governed evidence or facts.

### Dependencies

Expand Down
1 change: 1 addition & 0 deletions meta/executors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export { dispatch } from './dispatch';

// Side-effect imports: each executor file calls registerExecutor() at top level.
import './update-obligation-status';
import './legal-matter-bootstrap';
190 changes: 190 additions & 0 deletions meta/executors/legal-matter-bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* Executor: legal_matter_bootstrap
*
* Read-only bootstrap projection for a governed legal matter. Delegates case
* discovery/readiness to ChittyCounsel and returns the result for the dispatcher
* to record in cc_actions_log. It never writes evidence, facts, or matter state.
*
* Canonical URI:
* chittycanon://core/services/chittycommand/executors/legal_matter_bootstrap
*/

import { z } from 'zod';
import type { ExecutorContext, ExecutorRunOutput, IntentExecutor } from './types';
import { registerExecutor } from './registry';

export const LEGAL_MATTER_BOOTSTRAP_INTENT = 'legal_matter_bootstrap';

const DEFAULT_COUNSEL_URL = 'https://counsel.chitty.cc';
const BOOTSTRAP_TIMEOUT_MS = 10_000;

export const legalMatterBootstrapSchema = z.object({
case_chitty_id: z.string().min(1).max(128),
});

export type LegalMatterBootstrapArgs = z.infer<typeof legalMatterBootstrapSchema>;

interface BootstrapFetchOptions {
counselUrl?: string;
fetchFn?: typeof fetch;
}

export async function runLegalMatterBootstrap(
args: LegalMatterBootstrapArgs,
options: BootstrapFetchOptions = {},
): Promise<{
success: boolean;
found?: boolean;
bootstrap?: Record<string, unknown>;
case?: Record<string, unknown> | null;
provenance?: Record<string, unknown>;
error?: string;
upstream_status?: number;
}> {
const counselUrl = (options.counselUrl || DEFAULT_COUNSEL_URL).replace(/\/$/, '');
const fetchFn = options.fetchFn ?? fetch;
const url =
`${counselUrl}/case/${encodeURIComponent(args.case_chitty_id)}/bootstrap`;

let response: Response;
try {
response = await fetchFn(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'X-ChittyOS-Caller': 'chittycommand',
},
signal: AbortSignal.timeout(BOOTSTRAP_TIMEOUT_MS),
});
} catch (err) {
return {
success: false,
error: `ChittyCounsel unavailable: ${err instanceof Error ? err.message : String(err)}`,
};
}

let body: unknown;
try {
body = await response.json();
} catch {
return {
success: false,
upstream_status: response.status,
error: 'ChittyCounsel returned non-JSON bootstrap response',
};
}

if (!response.ok) {
const upstream = body as Record<string, unknown>;
return {
success: false,
upstream_status: response.status,
error:
typeof upstream?.error === 'string'
? upstream.error
: `ChittyCounsel bootstrap failed with HTTP ${response.status}`,
};
}

const parsed = z.object({
found: z.boolean(),
bootstrap: z.record(z.string(), z.unknown()),
case: z.record(z.string(), z.unknown()).nullable().optional(),
provenance: z.record(z.string(), z.unknown()),
}).safeParse(body);

if (!parsed.success) {
return {
success: false,
upstream_status: response.status,
error: 'ChittyCounsel bootstrap response failed contract validation',
};
}

return {
success: true,
found: parsed.data.found,
bootstrap: parsed.data.bootstrap,
case: parsed.data.case ?? null,
provenance: parsed.data.provenance,
};
}

const executor: IntentExecutor = {
intentType: LEGAL_MATTER_BOOTSTRAP_INTENT,
canonicalUri:
'chittycanon://core/services/chittycommand/executors/legal_matter_bootstrap',

async run(ctx: ExecutorContext): Promise<ExecutorRunOutput> {
if (ctx.intent.privilege !== 'privileged' || ctx.intent.space !== 'legalink') {
return {
ok: false,
description: 'Legal matter bootstrap refused: intent must be privileged + legalink',
actionType: 'legal_matter_bootstrap',
targetType: 'case',
targetId: null,
status: 'failed',
errorMessage: 'classification mismatch: expected privilege=privileged and space=legalink',
};
}

const parsed = legalMatterBootstrapSchema.safeParse(ctx.intent.payload);
if (!parsed.success) {
return {
ok: false,
description: `payload validation failed for intent ${ctx.intent.id}`,
actionType: 'legal_matter_bootstrap',
targetType: 'case',
targetId: null,
status: 'failed',
errorMessage: parsed.error.message,
};
}

const env = ctx.env as typeof ctx.env & { CHITTYCOUNSEL_URL?: string };
const result = await runLegalMatterBootstrap(parsed.data, {
counselUrl: env.CHITTYCOUNSEL_URL,
});

if (!result.success) {
return {
ok: false,
description: result.error ?? 'ChittyCounsel bootstrap failed',
actionType: 'legal_matter_bootstrap',
targetType: 'case',
targetId: null,
status: 'failed',
errorMessage: result.error ?? 'ChittyCounsel bootstrap failed',
responsePayload: result.upstream_status
? { upstream_status: result.upstream_status }
: undefined,
};
}

return {
ok: true,
description: `Read-only legal matter bootstrap completed for ${parsed.data.case_chitty_id}`,
actionType: 'legal_matter_bootstrap',
targetType: 'case',
targetId: null,
status: 'completed',
responsePayload: {
found: result.found,
bootstrap: result.bootstrap,
case: result.case,
provenance: result.provenance,
},
metadata: {
source_service: 'chittycounsel',
case_chitty_id: parsed.data.case_chitty_id,
read_only: true,
privilege: 'privileged',
space: 'legalink',
},
};
},
};

registerExecutor(executor);

export default executor;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type Env = {
CHITTYSCHEMA_URL?: string;
CHITTYCERT_URL?: string;
CHITTYEVIDENCE_URL?: string;
CHITTYCOUNSEL_URL?: string;
CHITTYEVIDENCE_TOKEN?: string;
CHITTY_CONNECT_TOKEN?: string;
CHITTYLEDGER_TOKEN?: string;
Expand Down
118 changes: 118 additions & 0 deletions tests/meta/legal-matter-bootstrap.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { describe, expect, it, vi } from 'vitest';
import executor, {
LEGAL_MATTER_BOOTSTRAP_INTENT,
runLegalMatterBootstrap,
} from '../../meta/executors/legal-matter-bootstrap';
import type { ExecutorContext } from '../../meta/executors/types';

describe('legal_matter_bootstrap executor', () => {
it('returns a validated read-only ChittyCounsel bootstrap response', async () => {
const fetchFn = vi.fn(async (url: string | URL | Request) => {
expect(String(url)).toContain('/case/03-1-USA-0010-L-2602-0-01/bootstrap');
return Response.json({
found: true,
bootstrap: {
case_found: true,
phases: ['BOOTSTRAP', 'DISCOVER'],
queues: ['INITIAL_ANALYSIS'],
},
case: { chitty_id: '03-1-USA-0010-L-2602-0-01' },
provenance: { worker: 'chittycounsel', version: '0.2.0' },
});
}) as typeof fetch;

const result = await runLegalMatterBootstrap(
{ case_chitty_id: '03-1-USA-0010-L-2602-0-01' },
{ counselUrl: 'https://counsel.example.test/', fetchFn },
);

expect(result.success).toBe(true);
expect(result.found).toBe(true);
expect(result.provenance).toMatchObject({ worker: 'chittycounsel' });
expect(fetchFn).toHaveBeenCalledOnce();
});

it('fails closed on upstream transport failure', async () => {
const fetchFn = vi.fn(async () => {
throw new Error('network down');
}) as unknown as typeof fetch;

const result = await runLegalMatterBootstrap(
{ case_chitty_id: '03-1-USA-0010-L-2602-0-01' },
{ fetchFn },
);

expect(result.success).toBe(false);
expect(result.error).toContain('ChittyCounsel unavailable');
});

it('refuses intents outside privileged + legalink classification', async () => {
const ctx = {
intent: {
id: 'intent-test',
intentType: LEGAL_MATTER_BOOTSTRAP_INTENT,
payload: { case_chitty_id: '03-1-USA-0010-L-2602-0-01' },
privilege: 'public',
space: 'business',
},
} as unknown as ExecutorContext;

const result = await executor.run(ctx);

expect(result.ok).toBe(false);
expect(result.status).toBe('failed');
expect(result.errorMessage).toContain('classification mismatch');
});

it('keeps the case ChittyID in metadata rather than UUID-only audit target_id', async () => {
const fetchMock = vi.fn(async () => Response.json({
found: true,
bootstrap: { case_found: true },
case: { chitty_id: '03-1-USA-0010-L-2602-0-01' },
provenance: { worker: 'chittycounsel', version: '0.2.0' },
}));
vi.stubGlobal('fetch', fetchMock);

const ctx = {
intent: {
id: 'intent-test',
intentType: LEGAL_MATTER_BOOTSTRAP_INTENT,
payload: { case_chitty_id: '03-1-USA-0010-L-2602-0-01' },
privilege: 'privileged',
space: 'legalink',
},
env: { CHITTYCOUNSEL_URL: 'https://counsel.example.test' },
} as unknown as ExecutorContext;

const result = await executor.run(ctx);

expect(result.ok).toBe(true);
expect(result.targetId).toBeNull();
expect(result.metadata).toMatchObject({
case_chitty_id: '03-1-USA-0010-L-2602-0-01',
source_service: 'chittycounsel',
read_only: true,
});

vi.unstubAllGlobals();
});

it('rejects an invalid payload before any upstream call', async () => {
const ctx = {
intent: {
id: 'intent-test',
intentType: LEGAL_MATTER_BOOTSTRAP_INTENT,
payload: {},
privilege: 'privileged',
space: 'legalink',
},
env: {},
} as unknown as ExecutorContext;

const result = await executor.run(ctx);

expect(result.ok).toBe(false);
expect(result.status).toBe('failed');
expect(result.errorMessage).toContain('case_chitty_id');
});
});
1 change: 1 addition & 0 deletions wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"CHITTYROUTER_URL": "https://router.chitty.cc",
"CHITTYAGENT_SCRAPE_URL": "https://chittyagent-scrape.ccorp.workers.dev",
"CHITTYEVIDENCE_URL": "https://evidence.chitty.cc",
"CHITTYCOUNSEL_URL": "https://counsel.chitty.cc",
"CHITTYGOV_URL": "https://gov.chitty.cc",
"CHITTYREGISTER_URL": "https://register.chitty.cc"
// PLAID_CLIENT_ID and PLAID_SECRET set via `wrangler secret put`
Expand Down
Loading