cto/skills/cto-angular-toolkit/SKILL.md
Svrnty 3a3503aa2e feat(cto): close Python+Angular stack gaps + PROFILE-DISTRIBUTION-PROTOCOL compliance
AGENT.md: REQUIRED T2 frontmatter per §2.1.
manifest.yaml: REQUIRED governance: block per §2.2. Register new toolkit skills.
install.sh: chmod +x.

skills/cto-python-toolkit/SKILL.md (v0.1): closes Python stack gap inline.
References real workspace projects as exemplars: scripts/sot-precommit.py
(single-file CLI), bte-mcp/server.py + bte_core.py (FastMCP server),
svrnty-hermes-webui-plugin (PEP 621 + pytest.ini_options), curator/sweep.py
(mode flags + dry-run + stdlib-heavy). Sandcastle prompt template + post-
run quality-gate routing via PG-svrnty.lib-quality-gates.

skills/cto-angular-toolkit/SKILL.md (v0.1): closes Angular stack gap inline.
Anchored to adwright/adwright-console as canonical Plan B Angular reference
(Angular 21.2 + signals + standalone components + inject() + gRPC-web via
@protobuf-ts/grpcweb-transport + L6-svrnty.lib-cqrs-datasource). Sandcastle
prompt template + DESIGN.md compliance check for UI work.

CONTRACT.md §6: Python+Angular promoted from  generic → 🟡 skill-only
(no more "gap" marker). Documents path to  deep when cortex/ libs extract.
skills/cto-agent/SKILL.md: routing table updated — Python/Angular rows now
route to the toolkit skills instead of falling through to generic.

CLAUDE.md: site-map footer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 12:37:11 -04:00

13 KiB

name description metadata
cto-angular-toolkit Use when the user mentions 'Angular code task', 'fix bug in Angular repo', 'implement feature in Angular', 'refactor Angular', 'ng', 'ng build', 'ng test', 'angular signal', 'standalone component', 'gRPC-web', 'foblex flow', or the target stack identified by cto-agent is Angular. Encodes Plan B's Angular 21 patterns (signals + standalone components + gRPC-web to .NET CQRS), anchored to the real Adwright console codebase. Closes the Angular stack gap in cto-planb.
version model hermes tier status owner source last_reviewed
0.1.0 qwen-local/qwen3.6-35b-a3b
requires_toolsets
terminal
memory_tool
T2 active jp hand 2026-05-24

CTO Angular Toolkit — Sandcastle Prompt + Plan B Patterns

Scope: routed-to by cto-agent when the target repo stack is Angular. Closes the Angular stack gap documented in CONTRACT.md §6. All patterns anchored to the real Adwright console codebase — the canonical Plan B Angular reference.

When CTO routes here

Per skills/cto-agent/SKILL.md per-stack routing table — Angular row. Triggers:

  • Target repo contains angular.json
  • package.json declares @angular/core dependency
  • Task description mentions Angular explicitly
  • cto-agent analyze step detects Angular as primary stack

The canonical Plan B Angular reference

adwright/adwright-console/ — the Adwright console, a federated sibling workspace (registered in workspace CLAUDE.md). Read this codebase before any Angular sandcastle invocation. Pulled facts (verified 2026-05-24):

Aspect Value
Angular version ^21.2.0
Component style Standalone (no NgModule) — @Component({ imports: [...] })
Reactivity Signalssignal(), computed(), inject()
Routing provideRouter(routes) in app.config.ts
Styles SCSS ("inlineStyleLanguage": "scss", prefix app)
Build builder @angular/build:application (modern Vite-based, not webpack)
Backend transport gRPC-web via @protobuf-ts/grpcweb-transport → .NET CQRS via L6-svrnty.lib-cqrs-datasource
Generated types src/app/gen/<service>/<version>/* from .proto files
Mock data src/app/core/mock-data.service.ts — dev pattern; mocks signal-typed
Graph UI lib @foblex/flow, @foblex/2d, @foblex/mediator (Adwright-specific — pattern not for every project)

Key files to study (point sandcastle agent at these):

Tooling baseline (always include in sandcastle prompt)

Tool Purpose Invocation Required? Notes from adwright
npm Package manager npm install / npm ci YES (adwright uses npm@11.6.2; no pnpm/yarn migration) Adwright pins "packageManager": "npm@11.6.2" in package.json
ng build Production build ng build YES — must succeed before PR Uses @angular/build:application builder
ng test Unit test runner ng test --watch=false --browsers=ChromeHeadless If tests exist (adwright skips tests by schematic default — match repo choice) Adwright has skipTests: true schematics — only add tests if explicitly scoped
ng lint Linter (eslint) ng lint If eslint configured Add it; default ng new projects don't include it
ng serve Dev server ng serve (CTO does NOT run this — sandboxed, no port forward) NO in sandcastle context Local dev only

Project layout pattern (per adwright-console)

<repo>/
├── angular.json                # workspace config — schematics defaults, builder selection
├── package.json                # pin Angular major; lock packageManager
├── tsconfig.json + tsconfig.app.json + tsconfig.spec.json
├── proxy.conf.json             # dev proxy to backend (CQRS at :5001 or similar)
├── public/                     # static assets (served as-is)
├── src/
│   ├── main.ts                 # bootstrapApplication(App, appConfig)
│   ├── index.html
│   ├── styles.scss             # global styles
│   └── app/
│       ├── app.ts              # standalone root component (signals)
│       ├── app.config.ts       # provideRouter + provider list
│       ├── app.routes.ts       # Routes array (lazy where appropriate)
│       ├── app.html / app.scss
│       ├── core/               # services — gRPC clients, mock data, models
│       │   ├── <name>.service.ts
│       │   └── models.ts       # shared TS types (do NOT duplicate proto types here)
│       └── gen/                # generated proto types — DO NOT edit by hand
│           └── <pkg>/<ver>/*.ts

Sandcastle prompt MUST tell the agent:

  • Use signals + standalone — no NgModule, no OnInit if computed() covers it
  • Inject via inject(), not constructor injection (modern Angular 16+ pattern)
  • Map proto enums → friendly TS string-literal unions in service layer (per cycles.service.ts CycleStatus pattern) — UI never sees CYCLE_STATUS_* constants
  • Mock-data services live in core/mock-data.service.ts during dev; swap to real gRPC client when backend ready
  • Never hand-edit src/app/gen/** — regenerate via proto pipeline (see L6-svrnty.lib-cqrs-datasource patterns)
  • Match existing schematics — adwright defaults skipTests: true, prefix app, style scss. New components must match.

Sandcastle invocation template (Angular)

SANDCASTLE_REPO="${SANDCASTLE_REPO:-$HOME/workspaces/hermes/sandcastle}"
cd "$SANDCASTLE_REPO"
npx tsx -e "
import { run, claudeCode } from '@ai-hero/sandcastle';
import { docker } from '@ai-hero/sandcastle/sandboxes/docker';
const result = await run({
  agent: claudeCode('claude-opus-4-7'),
  sandbox: docker({
    image: 'node:22-slim',
    setup: [
      'apt-get update && apt-get install -y chromium-browser || true',
      'cd /workspace && npm ci'
    ]
  }),
  promptFile: '${CTO_HOME}/work/${WORK_ID}/prompt.md',
  cwd: '${TARGET_REPO}',
  branchStrategy: { type: 'branch', branch: 'cto/${WORK_ID}' },
  maxIterations: 5,
});
console.log(JSON.stringify({ commits: result.commits, branch: result.branch }, null, 2));
"

Prompt file (prompt.md) MUST instruct the sandboxed agent to:

  1. Read angular.json — note builder (@angular/build:application for v17+; webpack-based for older), schematics defaults, prefix
  2. Read package.json — note Angular major version, packageManager pin
  3. Reference Adwright patterns at adwright/adwright-console/src/app/{app.ts, core/cycles.service.ts} for component + service shape
  4. Make code changes per the brief — match existing standalone + signals + inject() patterns
  5. Run ng lint if configured — must pass
  6. Run ng build — must succeed (this catches type errors + template errors)
  7. Run ng test --watch=false --browsers=ChromeHeadless if tests exist
  8. Commit + report

Post-run quality gates (mount PG-svrnty.lib-quality-gates if available)

After sandcastle completes, run quality gates against the diff:

QG=/home/svrnty/workspaces/cortex/PG-svrnty.lib-quality-gates
[ -d "$QG" ] && "$QG/bin/run-gates" --stack typescript --repo "${TARGET_REPO}" --branch "cto/${WORK_ID}"

The lib-quality-gates TypeScript/Angular suite (per CORTEX-TOOLING.md) covers:

  • Strict TypeScript config validation (strict: true, noImplicitAny, etc.)
  • Bundle size budgets (angular.json → architect.build.options.budgets)
  • Accessibility lint (axe / Angular ESLint a11y rules)
  • Dep vulns (npm audit --production)

If gates fail: re-prompt sandcastle with violations, max 3 iterations, then escalate to JP.

DESIGN.md compliance (Angular UI + Stitch consumers)

Per CONTRACT.md §7, when CTO sandcastle-orchestrates Angular UI work AND the output feeds DESIGN.md-aware tools (Stitch, others), components MUST conform to the 8-property DESIGN.md subset: backgroundColor, textColor, typography, rounded, padding, size, height, width.

Workflow:

  1. CTO ensures sandcastle agent emits components compatible with the 8-property contract
  2. Post-build, run pi-bte-plugin design-md-exporter to emit BRAND-DESIGN.md from the brand's DTCG token set
  3. Validate: npx --yes @google/design.md@latest lint BRAND-DESIGN.md
  4. If validation fails: re-prompt sandcastle with the lint error + the 8-property contract

Concrete adwright opportunity: the @foblex/flow graph nodes could expose their styles via DESIGN.md tokens (currently they don't — that's a future task scope, not implicit in every Adwright task).

Worked example — add a route to adwright-console

Task: "Add a /profiles route that lists Hermes profile distributions (from svrnty-hermes-webui-plugin's /api/profile-catalog)."

Sandcastle prompt would:

  1. Mount /home/svrnty/workspaces/hermes/adwright/adwright-console/ as cwd
  2. Reference src/app/core/cycles.service.ts as the gRPC-service pattern — but note: this new endpoint is REST/JSON (svrnty-plugin route), not gRPC. So use HttpClient (provideHttpClient() added to app.config.ts) instead of gRPC-web transport.
  3. Generate component: ng generate component features/profiles --standalone --skip-tests (matches adwright defaults)
  4. Add route in app.routes.ts: { path: 'profiles', loadComponent: () => import('./features/profiles/profiles').then(m => m.Profiles) }
  5. Inject HttpClient via inject(HttpClient); signal-typed response
  6. Run ng build
  7. Commit on branch cto/<work-id>, open PR

Anti-patterns (sandcastle prompt MUST forbid)

  • NgModule (@NgModule({...})) — use standalone components only (Angular 21+ pattern)
  • Constructor injection (constructor(private svc: MyService)) — use inject()
  • BehaviorSubject for UI state — use signal() (RxJS only for stream-of-events, not state)
  • Hand-editing src/app/gen/** — regenerate from proto sources
  • Adding tests when repo schematics declare skipTests: true — match the repo choice; only add tests if task scope explicit
  • Bumping Angular major version (e.g., 21 → 22) without JP approval — major framework bumps = JP decision
  • Adding heavy UI libs (Material/PrimeNG/etc.) without explicit task scope — Adwright is intentionally lean
  • Editing proxy.conf.json to bypass auth or hit prod backends — dev-only file
  • <div [innerHTML]="..." without DomSanitizer — XSS risk

Stack gap roadmap

This skill closes the Angular gap inline. The future path:

  1. v0.x: this inline-pattern skill (CURRENT) — anchored to adwright-console
  2. v1.x: extract canonical patterns into cortex/L6-svrnty.lib-angular-framework (deferred — adwright is the only Angular consumer today)
  3. When extracted: replace skill body with mount cortex/L6-svrnty.lib-angular-framework

Until then, adwright-console is the framework reference. If adwright pattern conflicts with this doc, adwright wins — update this doc to match.