// overview

AI layer overview

The staff7 AI layer is an intelligence interface built directly on top of the platform's live data. It lets users query their staffing, financial, and operational data in plain language — and act on it directly from the console.

AI Console
Terminal-style chat interface. Type questions or use structured /commands to load specific context.
Agentic actions
Approve leaves, update project status, assign consultants — directly from the console with a confirmation step.
RLS-aware queries
The agent uses your session JWT — it can only see your company's data. RLS enforces tenant isolation.
Bring your own model
Connect any Ollama-compatible model: local (privacy-first) or cloud (kimi-k2.5, llama3, mistral…).
// console

AI Console

The console is a terminal-style chat interface accessible from the sidebar under Agents. It maintains conversation history within the session and streams responses in real time.

/
Command menu
Type / to open the structured command browser. Select a command to pre-load the right data context.
Streaming cursor
Responses appear character-by-character. The ▋ cursor shows the agent is still generating.
Clear history
Clear button resets the conversation history. The agent starts fresh without prior context.
Agent status bar
Shows which sub-agents are ONLINE / THINKING / IDLE at a glance.
The console uses SSE (Server-Sent Events) to stream the Ollama response. The route at /api/ai proxies to Ollama and reformats NDJSON chunks as SSE events. Actions use a separate PUT /api/ai endpoint.
/
// commands

Commands

Commands pre-load specific Supabase context before sending your message. Without a command, the agent loads a general staff + profitability summary. With a command, it fetches the most relevant data for your question.

/staff.benchAvailable consultants + occupancy + pending leaves + profitability summarystaff
/staff.allAll consultants + active projects + full profitabilitystaff
/leave.checkPending leave requests with consultant detailsleave
/fin.marginProject margins and daily rates + profitability view per consultantfin
/timesheet.weekCurrent week timesheet status — all consultantstimesheet
/profit.analysisFull profitability analysis: margins, target gaps, freelance vs employeeprofit
Commands use prefix matching/staff.bench and /staff.all both load the /staff context. The sub-label after the dot is passed to the agent as a hint to focus its response.
// actions

Agentic actions

The action agent uses native tool calling (kimi-k2.5 supports it natively) to detect write intentions and execute them with a confirmation step. No action is executed without explicit user confirmation.

Intent detection
The router detects action keywords (approve, refuse, assign, update) and routes to the action agent instead of the query agent.
Confirmation UI
A card appears in the terminal showing the action and its parameters. The user must click CONFIRM before anything is written.
Activity log
Every executed action is written to the activity feed with a "via AI" tag — full audit trail.
Role-gated
Actions are only available to admin and super_admin roles. Managers and consultants cannot trigger write operations.
approve_leaveApprove a pending leave requestconsultant_name, leave_id?
refuse_leaveRefuse a pending leave requestconsultant_name, reason?
update_project_statusUpdate a project's statusproject_name, status
assign_consultantAssign a consultant to a projectconsultant_name, project_name, allocation?
// Example flow
User    > "approve Clara's leave"
ACTION  > ⚠ Approve leave request
           consultant_name: Clara Kim
           [ CONFIRM ]  [ CANCEL ]

User    > CONFIRM
STAFF7  > ✓ Leave request approved for Clara Kim —
           CP from 2026-03-14 to 2026-03-18 (5 days).
The action agent calls the model with temperature: 0 for deterministic tool selection. Ambiguous messages always fall back to the query agent — false positives are prevented by requiring explicit action keywords.
// context

Live context injection

Every request to /api/ai fetches fresh data from Supabase and injects it into the system prompt. The agent always sees current data — no stale cache, no manual sync.

CommandTables / views queriedKey fields
/staffconsultant_occupancy, leave_requests, consultant_profitabilitystatus, contract_type, actual_cost, target_rate, occupancy_rate
/finproject_financials, consultant_profitabilitysold_rate, margin_pct, revenue, gross_margin
/profitconsultant_profitability, consultant_occupancyFull profitability + pre-computed summary aggregates
/timesheetconsultant_occupancy, timesheetsdate, value, status — current week only
/leaveleave_requests, consultant_occupancypending only, limit 30
// System prompt structure (every request)
SYSTEM_PROMPT          // role + rules + field glossary
--- LIVE DATA ---
{ consultants: [...], profitability_summary: {...} }
--- END ---
[conversation history]
[new user message]
// profitability

Profitability AI

The /profit.analysis command loads the richest context — the full consultant_profitability view plus pre-computed aggregates — enabling questions that span finance, staffing, and contract type.

Margin analysis
"Which consultant is the least profitable?" — sorted by margin % with full cost breakdown.
Target gap
"Who is not hitting their target daily rate?" — compares target vs actual cost, flags < 10% margin.
Freelance vs employee
"How many freelancers do I have and what is their average cost?" — contract type across all contexts.
Risk surface
"Which consultants are under-occupied with a low margin?" — cross-metric analysis.
// Pre-computed summary injected into /profit context
{
  total_consultants: 11,
  employees: 8,
  freelances: 3,
  total_ca: 312000,
  total_marge: 142000,
  avg_marge_pct: "34.2",
  below_target_count: 2,
  below_target: [
    { name: "David Mora",    tjm_cout: 680, tjm_cible: 700 },
    { name: "Lucas Martin",  tjm_cout: 450, tjm_cible: 460 }
  ]
}
// privacy

Privacy & model choice

staff7 is designed around privacy-by-design. You choose where your data goes — local model or cloud API.

ModeData leaves your infra?Setup
Local OllamaNever — model runs on your serverInstall Ollama, set OLLAMA_HOST=http://localhost:11434
Ollama CloudYes — sent to Ollama Cloud APISet OLLAMA_HOST + OLLAMA_API_KEY
Any OpenAI-compat.Yes — sent to third-party APIPoint OLLAMA_HOST to any compatible endpoint
# .env.local
OLLAMA_HOST=http://localhost:11434   # local model
OLLAMA_MODEL=llama3.2:3b            # or mistral, phi3, etc.
OLLAMA_API_KEY=                     # empty for local

# or cloud
OLLAMA_HOST=https://ollama.com
OLLAMA_MODEL=kimi-k2.5:cloud
OLLAMA_API_KEY=sk-...
// rls

RLS & tenant isolation

The AI query route does not use the Supabase service role key for reads. It uses the authenticated user's JWT — so RLS policies apply to every query the agent makes. Write operations (actions) use the service role key server-side, after role verification.

// /api/ai — JWT extraction (query agent)
const authHeader = req.headers.get('Authorization') ?? ''
const userToken  = authHeader.replace('Bearer ', '').trim()

// Supabase query headers — RLS applied
const h = {
  'apikey':        anonKey,
  'Authorization': `Bearer ${userToken}`,
}

// Action agent — service role after role check
if (role !== 'admin' && role !== 'super_admin') return 403
// → executes with service role key
The client sends the token via Authorization: Bearer <session.access_token>. If the session has expired, the route returns an SSE error: "Session expired — please sign in again."
// mcp

MCP integration (roadmap)

The Model Context Protocol (MCP) is planned as the next evolution of the AI layer — standardising tool calls across models and enabling external integrations.

MCP server
A FastAPI-based MCP server will expose tools: get_consultants, get_profitability, approve_leave, etc. — replacing direct REST calls.
External sources
Connect Google Calendar, Slack, or Pennylane as MCP tools — the agent queries them alongside your Supabase data.
Model-agnostic
MCP is a standard protocol. Any compatible model (Claude, GPT-4o, Gemini) can use the same tool definitions.
Auth passthrough
MCP server validates the JWT before executing any tool — same RLS isolation as the current approach.
The current action agent already implements the core pattern — native tool calling with confirmation. MCP will standardise and extend this with external integrations and a dedicated FastAPI layer.