Aravind 55ddaa134a refactor(ts-migration): Phase 11 batch 4 — the agent layer
All thirteen modules under `src/lib/agents/`. Renamed and annotated; no
logic touched. 13/13 erase to byte-identical JavaScript, and the bundle
still hashes to 74d17e2d…

Project typecheck errors are now 9, down from the 20 this phase started
from. Nothing was suppressed: batch 3's `Frontmatter` cleared 4 and this
batch's annotations cleared 7 more that had been sitting in `agentStore`,
`runtime` and `useAgents` since before the migration.

Two findings, both recorded rather than fixed:

`agentSkillIds(agent)` takes one parameter and is called with two, at
`runtime.ts:83` and `:95`. Not a bug — its own doc comment says so:
subagent skills were deliberately removed from it, because CLAUDE.md §3
makes `subagents` a delegation list rather than a skill list, and
"`agents` is still accepted so every call site keeps working; it is no
longer read." The contract is restored with an overload signature, which
emits no JavaScript — confirmed by reading the emitted output, where
`agentSkillIds` still takes exactly one parameter. Worth knowing that
`agentScopedDisabledWith` therefore computes what `agentScopedDisabled`
computes; that is intended, and `skill-check.mjs` asserts the behaviour
at eleven call sites.

`useAgents` returns five different shapes from eleven `return`
statements, which is the latent problem the migration plan predicted
here. `AgentActionResult` writes them down, but open: `ok` plus four
optional fields. Nothing stops a caller reading `.agent` off a failure
and getting `undefined` — `AgentDetail.jsx` reads `.conflict` and
`.error` off the same value. Closing it properly needs `as const` on
eleven literals so `ok` stops widening to `boolean` and starts
discriminating, which is an edit to these function bodies and not
something a rename may do. The type is the record of the decision, not
the decision.

Writing that interface also corrected my own count. I described four
shapes; the compiler rejected `duplicate`'s `{ ...result, id }` and made
it five.

Other annotations: React Query v5 infers `void` for an unconstrained
`mutationFn` parameter, so both mutations in `agentStore` had their
variables stated; `existingIds = []` in `agentLifecycle` infers
`undefined[]`, which rejects `.includes(id)`, so it is `string[]`; two
accumulators and two inline JSDoc hatches restated as annotations.

Measured against `fc8d7ee`:

  typecheck   9 errors, down from 16; no new error anywhere
  lint        exit 0, 0 errors, 289 warnings
  npm test    1684/1691, the same 7 failures verbatim
  build       exit 0, identical bundle hash
  type erasure  46/46 byte-identical across Phase 11 so far

No baseline artifact touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
2026-09-18 15:25:35 +05:30
2026-08-07 23:53:15 +05:30
2026-08-28 13:52:59 +05:30
2026-09-05 10:46:06 +05:30
2026-08-19 17:36:27 +05:30
2026-08-10 14:37:51 +05:30
2026-08-25 18:56:07 +05:30
2026-08-28 11:02:02 +05:30
2026-08-28 11:02:02 +05:30
2026-08-24 20:06:11 +05:30
2026-08-07 23:53:15 +05:30
2026-08-28 11:02:02 +05:30
2026-08-17 17:33:56 +05:30
2026-08-10 15:53:53 +05:30
2026-08-07 23:53:15 +05:30
2026-08-13 21:41:14 +05:30
2026-08-25 18:56:07 +05:30

KROW Demo

AI-powered hiring for event and hospitality staffing — a standalone demo build of KROW Forge.

Runs with no backend, no API keys and no real login. npm install && npm run dev and the app is fully populated.

npm install
npm run dev      # http://localhost:5173 — opens on /admin/login

Stack

Vite 6 · React 19 · React Router 6 · React Query 5 · Tailwind + shadcn/ui · Framer Motion · Recharts + MUI X Charts · react-hot-toast.

Structure

src/
  main.jsx        entry — mounts <App/>, imports index.css
  App.jsx         providers + the entire route table
  index.css       design tokens (HSL CSS variables) + utility layers

  api/            the backend seam — see below
    base44Client.js   the contract the production app talks to
    store.js          in-memory entity store, mirrored to localStorage
    aiEngine.js       local, deterministic InvokeLLM
    seed.js           demo dataset
    attendanceSeed.js shift/attendance dataset

  lib/            domain logic and data hooks
    krowHooks.js      React Query hooks over the entity store
    krowAi.js         AI workflows
    krowScore.js      score engine
    AuthContext.jsx   auth provider
    admin/            admin session, permissions, position insights
    skills/           the Owliver skill system (registry, resolver, flows)
    agents/           the agent system (registry, runtime, lifecycle)

  skills/         *.md skill definitions   — loaded by import.meta.glob
  agents/         *.md agent definitions   — loaded by import.meta.glob

  components/
    ui/           23 shadcn primitives
    ds/           30 design-system components (the app's real vocabulary)
    admin/        admin page shell + role glyphs
    krow/         domain components (+ talent/, proving/)
    charts/       MUI X Charts wrappers and theme
    agents/       agent configure / canvas / test panel
    forge/        KROW Forge skill + challenge components
    skills/       skill authoring surfaces
    ai-assistant/ Owliver — panel, routing, capabilities, history

  layouts/        AdminLayout — header nav, ⌘K search, assistant panel
  pages/          route components (admin/ holds the live product)
  hooks/          shared hooks
  assets/         brand asset references

Routes

The app opens on /admin/login. Everything else lives under /admin/* behind two guards: ProtectedRoute (auth) and AdminRoute (admin session), rendered inside AdminLayout.

Path Page
/admin/login Admin sign-in — outside the protected boundary
/admin Control Center
/admin/positions, positions/new, positions/:id Positions, Create, Detail
/admin/candidates, candidates/:id Candidates, Candidate Intelligence profile
/admin/hired · /admin/talent-pool Hired History, Talent Pool
/admin/university, university/:id KROW Forge, challenge detail
/admin/analytics · /admin/activity Analytics, Activity
/admin/profile · /admin/settings Profile, Settings
/admin/workspace Workspace hub
/admin/workspace/agents, agents/new, agents/:id Agent list, agent editor
/admin/workspace/skills, skills/new, skills/:id UI skill list and editor
/admin/workspace/skills/owliver/new, owliver/:id Owliver skill editor
/admin/workspace/skill-development Skill Development
* lib/PageNotFound.jsx

Legacy top-level paths (/overview, /positions, /candidates, /hired, /talent-pool, /university, /analytics, /activity, /tracking) all Navigate into their /admin/* equivalent, id preserved. Static route segments are declared before dynamic ones so workspace/agents/new cannot be read as an agent whose id is "new".

Note. App.jsx still imports a set of pre-redesign Employer/Talent pages (Overview, Apply, WorkerProfile, KrowIdentity, EmployeeDashboard, DesignSystem, …) and layouts/Layout.jsx. None of them are mounted on a route — they are unreachable at runtime and retained pending a decision on whether to re-route or remove them.

The backend seam

The production app talks to a Base44 backend through src/api/base44Client.js. This demo keeps that module path, export name and full method contract, and swaps only the transport:

Contract Demo implementation
base44.entities.<Name>.list/filter/get/create/update/delete api/store.js — in-memory records, mirrored to localStorage
base44.integrations.Core.InvokeLLM api/aiEngine.js — local, deterministic
base44.integrations.Core.UploadFile blob URLs, session-scoped
base44.auth.* seeded employer/admin user, always signed in

Because the seam did not move, everything above it — lib/krowHooks.js, lib/krowAi.js, lib/krowScore.js, every page and component — is unchanged from the reference implementation.

The AI engine

Every AI workflow funnels through one call, InvokeLLM({ prompt, response_json_schema }). api/aiEngine.js reimplements it locally: it recognises each workflow by the phrase its prompt opens with, reads the structured fields the prompt already carries (Years Experience: 6, Required Certifications: …, the talent-pool JSON block) and scores them deterministically.

Nine workflows are implemented: candidate screening, job-description generation, résumé building, interview questions, interview evaluation, talent matching, Owliver's conversation, Career DNA building and Proving Ground evaluation. Results respond to the data rather than being canned — the same input always returns the same output.

Skills and agents

Two registries discover their definitions from markdown at build time:

Registry Glob Files
lib/skills/registry.js import.meta.glob('/src/skills/**/*.md') 18 Owliver skills, 5 workforce training skills
lib/agents/registry.js import.meta.glob('/src/agents/**/*.md') 9 agent definitions

These globs are absolute paths. Moving or renaming src/skills/ or src/agents/ makes the registry silently return nothing — no build error, no import failure, just an empty registry. Add definitions by dropping a new .md file into the right folder; nothing else needs to change.

Demo data

Seeded in src/api/seed.js — positions, applicants, AI-scored candidates, interviews, hires, talent-pool profiles, Proving Ground courses and an activity log; shift data in src/api/attendanceSeed.js.

Edits persist to localStorage. To restore the shipped dataset:

// in the browser console
localStorage.removeItem('krow_demo_db'); location.reload();

Bumping STORAGE_VERSION in src/api/store.js (currently 8) invalidates saved snapshots automatically, so changing the seed does not require a manual clear.

Design system

Tokens live in src/index.css as HSL CSS variables consumed by tailwind.config.js.

Token Value
Primary — KROW Blue #0A39DF
Accent — KROW Yellow #F9E547
Pale Yellow #F8E08E
Dark Navy #333F48
Mint #D1E0D7
Radius 0.75rem
Headings Sora
Body Inter

src/components/ds/ is the vocabulary the app actually writes in — Surface, KpiCard, DataTable, PageHeader, Modal, toast and the rest, exported through ds/index.js. src/components/ui/ holds the shadcn primitives those are built on. Surfaces use glass and glass-card; the page background is the gradient-mesh utility.

Toasts go through ds/toast (a wrapper over react-hot-toast), rendered by <HotToaster> in App.jsx.

Scripts

Command Purpose
npm run dev Dev server (honors PORT, default 5173)
npm run build Production build
npm run preview Serve the build
npm run lint ESLint — currently clean
npm run lint:fix ESLint with --fix
npm test scripts/skill-check.mjs — 835 assertions over the skill and agent systems
npm run typecheck tsc -p ./jsconfig.json with checkJs

The test harness

npm test boots a real Vite dev server in middleware mode and ssrLoadModules the actual application modules, so it exercises the real @/ alias and import.meta.glob pipeline rather than mocks. It also diffs Owliver's behaviour across eleven page contexts against a committed snapshot, scripts/__baseline__/owliver-baseline.json; regenerate that deliberately with node scripts/owliver-baseline.mjs --write, never to turn a red check green.

Because it loads modules by absolute path, the harness pins the locations of src/api/, src/lib/, src/lib/skills/, src/lib/agents/, src/components/ai-assistant/, src/App.jsx, src/layouts/AdminLayout.jsx and a handful of agent files. Move any of them and update scripts/owliver-capture.mjs and scripts/skill-check.mjs in the same change.

Known-failing checks

Two checks fail on a clean checkout and are tracked as separate work, not regressions:

  • npm test — 834/835 pass; the seeded overtime climb is found fails.
  • npm run typecheck — 59 errors, all pre-existing JSDoc/inference gaps in lib/krowAi.js, lib/skills/*, lib/positionModel.js and a few components.

Deployment

Dockerfile builds with node:22-alpine (capped at 1 GB heap for small hosts) and serves the static dist/ from nginx:alpine using nginx.conf — gzip, immutable /assets/ caching and an SPA fallback to index.html so client-side routes resolve on refresh.

Description
No description provided
Readme 7.2 MiB
Languages
TypeScript 81.1%
JavaScript 15.7%
HTML 2.6%
CSS 0.5%