Local-first, multi-tenant workflow automation product. Connect Outlook, run AI-planned workflows (tasks + HTTP APIs), and gate sensitive actions behind approvals.
Runs on your machine (127.0.0.1) with SQLite. Designed to grow into hosted Postgres + proper OAuth refresh later.
cd C:\Users\sherl\projects\workflow-agent
copy .env.example .env
# Edit .env: set JWT_SECRET, TOKEN_ENCRYPTION_KEY, optional OPENAI_API_KEY and Azure app credentials
npm install
cd web && npm install && cd ..
npm run db:migrate
npm run build:web
npm run dev- Dashboard: http://127.0.0.1:3847 (built UI served by the API)
- Dev (hot reload UI): run
npm run dev:all— API on 3847, Vite on 5173 (proxies/api)
Server default: http://127.0.0.1:3847
POST /api/auth/register
Content-Type: application/json
{
"email": "you@company.com",
"password": "your-password",
"name": "You",
"orgName": "Acme"
}Save the token and orgId from the response. Use Authorization: Bearer <token> on later calls.
- Azure Portal → App registrations → New registration.
- Redirect URI (Web):
http://127.0.0.1:3847/api/connections/microsoft/callback - API permissions:
Mail.Read,Mail.ReadWrite,Mail.Send,User.Read,offline_access. - Create a client secret; put Application (client) ID and secret in
.env:
AZURE_CLIENT_ID=...
AZURE_CLIENT_SECRET=...
AZURE_TENANT_ID=common
BASE_URL=http://127.0.0.1:3847- Open in browser (while logged in with your JWT — use a REST client that follows redirects, or paste the URL):
GET /api/orgs/{orgId}/connections/microsoft/start
Authorization: Bearer <token>POST /api/orgs/{orgId}/workflows
Authorization: Bearer <token>
{
"name": "Inbox triage",
"instruction": "List my 5 newest unread emails. For each important one, create a task titled with the subject. Do not send email.",
"autonomyMode": "approve_sensitive"
}POST /api/workflows/{workflowId}/run
Authorization: Bearer <token>
{ "input": "Monday morning triage" }| Mode | Behavior |
|---|---|
auto |
Run all tools immediately |
approve_sensitive |
Pause before send-email and HTTP calls (default) |
approve_all |
Pause before every tool |
When paused, approve via:
POST /api/approvals/{approvalId}/decide
{ "decision": "approve" }By default only localhost / 127.0.0.1 are allowed until you add hosts:
POST /api/orgs/{orgId}/allowed-hosts
{ "host": "api.example.com" }Triggers (manual / schedule / webhook)
→ Planner (OpenAI or built-in fallback)
→ Policy (autonomy mode)
→ Tool executor (Outlook, tasks, HTTP)
→ SQLite (runs, steps, approvals)
outlook_list_unread,outlook_send_email,outlook_draft_replytask_create,task_list,task_complete(org-scoped SQLite tasks)http_request(allowlisted hosts)
Swap the task backend for Todoist/Linear by adding a provider under src/integrations/tasks/.
- Microsoft token refresh (MSAL cache)
- Web UI + team invites
- Webhook triggers + cron scheduler process
- Postgres + encryption at rest for production deploy
- Per-org API keys for external callers
Change JWT_SECRET and TOKEN_ENCRYPTION_KEY before sharing the machine. Never commit .env. For production, use HTTPS, Postgres, and a secrets manager.