{"slug": "how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent", "title": "How to Build an AI Employee With a Knowledge Graph (Not Just Another Agent)", "summary": "A developer detailed how to build an AI employee using a knowledge graph, contrasting it with typical AI agents. The approach, exemplified by the Roster project, uses a graph to store state, ownership, and history, enabling agents to work across extended periods by waking on events, reasoning, acting, and recording results. The post includes a minimal TypeScript implementation and a scheduling mechanism for future tasks.", "body_md": "An AI agent can take an action. An AI employee needs to know what happens next.\n\nMost AI agents look something like this:\n\n```\nThink → Act → Observe → Repeat\n```\n\nThat's fine for short-lived tasks.\n\nBut an AI employee needs to work across hours, days, and weeks.\n\nIt needs to remember:\n\nThat's where graph engineering becomes interesting.\n\nThis is the architecture behind\n\n[Roster](https://get-roster.com):\n\nsoftware that can own work the way an employee does, not just fire off a single tool call.\n\nEvents wake someone up. A graph holds state, ownership, and history.\n\nThe agent reasons, acts, writes the result back, then sleeps until the next event.\n\nFor Roster, the loop looks like this:\n\n```\nEvent\n  ↓\nGraph\n  ↓\nAgent\n  ↓\nAction\n  ↓\nGraph Update\n  ↓\nSleep\n  ↓\nWake Again\n```\n\nLet's build a tiny version.\n\nImagine an AI employee called Maya.\n\nHer job is simple:\n\n**Follow up with sales leads.**\n\nHer world contains:\n\n```\nMaya\n  ↓ owns\nLead\n  ↓ belongs_to\nCompany\n  ↓ contacted\nEmail\n  ↓ replied_to\nCustomer\n```\n\nWe don't need a massive graph database.\n\nWe just need nodes and relationships.\n\nHere's a minimal TypeScript graph:\n\n```\ntype Node = {\n  id: string;\n  type: string;\n  data: Record<string, unknown>;\n};\n\ntype Edge = {\n  from: string;\n  to: string;\n  type: string;\n};\n\nclass Graph {\n  nodes = new Map<string, Node>();\n  edges: Edge[] = [];\n\n  addNode(node: Node) {\n    this.nodes.set(node.id, node);\n  }\n\n  connect(from: string, type: string, to: string) {\n    this.edges.push({ from, type, to });\n  }\n\n  neighbors(id: string) {\n    return this.edges\n      .filter((edge) => edge.from === id)\n      .map((edge) => ({\n        relationship: edge.type,\n        node: this.nodes.get(edge.to),\n      }));\n  }\n}\n```\n\nNow create Maya and a lead:\n\n``` js\nconst graph = new Graph();\n\ngraph.addNode({\n  id: \"maya\",\n  type: \"employee\",\n  data: {\n    name: \"Maya\",\n    role: \"sales\",\n  },\n});\n\ngraph.addNode({\n  id: \"lead-123\",\n  type: \"lead\",\n  data: {\n    company: \"Acme\",\n    status: \"qualified\",\n  },\n});\n\ngraph.connect(\"maya\", \"owns\", \"lead-123\");\n```\n\nOur graph now knows:\n\n```\nMaya ──owns──→ Lead #123\n```\n\nThat's already more useful than two disconnected database records.\n\nEmployees shouldn't constantly run.\n\nSomething should wake them up.\n\nFor example, Sarah replies to an email:\n\n``` js\nconst event = {\n  id: \"event-1\",\n  type: \"email.replied\",\n  data: {\n    leadId: \"lead-123\",\n    message: \"Sounds interesting. Follow up next Tuesday.\",\n  },\n};\n```\n\nNow we can find the employee responsible for that lead:\n\n``` js\nfunction findOwner(event: typeof event) {\n  const leadId = event.data.leadId;\n  return graph.edges.find(\n    (edge) => edge.to === leadId && edge.type === \"owns\"\n  )?.from;\n}\n\nconst employeeId = findOwner(event);\nconsole.log(employeeId);\n// maya\n```\n\nWe just answered:\n\n**Who should wake up?**\n\nThe flow becomes:\n\n```\nEmail Reply\n    ↓\nEvent\n    ↓\nFind Lead\n    ↓\nFind Owner\n    ↓\nWake Maya\n```\n\nNow we give Maya an actual agent loop.\n\n``` js\nasync function runEmployee(employeeId: string, event: any) {\n  const employee = graph.nodes.get(employeeId);\n  const context = {\n    employee,\n    event,\n    relationships: graph.neighbors(employeeId),\n  };\n\n  const decision = await agent(context);\n  const result = await execute(decision);\n\n  recordResult(employeeId, decision, result);\n}\n```\n\nThe important part is the sequence:\n\n```\nWake\n ↓\nRead Graph\n ↓\nReason\n ↓\nAct\n ↓\nRecord\n```\n\nThe graph gives the agent persistent context.\n\nNow imagine Sarah says:\n\nFollow up with me next Tuesday.\n\nMaya shouldn't stay running until Tuesday.\n\nShe schedules a future event.\n\n``` js\ntype Job = {\n  employeeId: string;\n  runAt: Date;\n  event: any;\n};\n\nconst jobs: Job[] = [];\n\nfunction schedule(job: Job) {\n  jobs.push(job);\n}\n```\n\nMaya can schedule her next action:\n\n```\nschedule({\n  employeeId: \"maya\",\n  runAt: new Date(\"2026-09-01T09:00:00Z\"),\n  event: {\n    id: \"followup-1\",\n    type: \"followup.due\",\n    data: {\n      leadId: \"lead-123\",\n    },\n  },\n});\n```\n\nThen Maya sleeps.\n\nWhen the time arrives:\n\n``` js\nasync function processJobs() {\n  const now = new Date();\n  for (const job of jobs) {\n    if (job.runAt <= now) {\n      await runEmployee(job.employeeId, job.event);\n    }\n  }\n}\n```\n\nNow we have two ways to wake an employee:\n\n```\nCustomer Reply ──────┐\n                     │\nApproval Granted ────┼──→ Wake Employee\n                     │\nSchedule Due ────────┘\n```\n\nNow let's connect an LLM.\n\nThe agent gets the relevant graph context and decides what to do.\n\n``` js\nasync function agent(context: any) {\n  const prompt = `\nYou are Maya, a sales employee.\nYour job is to follow up with leads.\n\nEvent:\n${JSON.stringify(context.event)}\n\nGraph:\n${JSON.stringify(context.relationships)}\n\nDecide the next action.\nReturn JSON:\n{\n  \"action\": \"...\",\n  \"reason\": \"...\",\n  \"runAt\": \"...\"\n}\n`;\n\n  return llm.generateObject(prompt);\n}\n```\n\nFor Sarah's message, Maya might return:\n\n```\n{\n  \"action\": \"schedule_followup\",\n  \"reason\": \"Sarah requested a follow-up next Tuesday.\",\n  \"runAt\": \"2026-09-01T09:00:00Z\"\n}\n```\n\nThen we execute it:\n\n```\nasync function execute(decision: any) {\n  switch (decision.action) {\n    case \"schedule_followup\":\n      schedule({\n        employeeId: \"maya\",\n        runAt: new Date(decision.runAt),\n        event: {\n          id: crypto.randomUUID(),\n          type: \"followup.due\",\n          data: decision,\n        },\n      });\n      return {\n        success: true,\n      };\n    case \"send_email\":\n      return sendEmail(decision);\n    default:\n      throw new Error(`Unknown action: ${decision.action}`);\n  }\n}\n```\n\nFinally, record what happened:\n\n```\nfunction recordResult(employeeId: string, decision: any, result: any) {\n  graph.addNode({\n    id: crypto.randomUUID(),\n    type: \"agent_action\",\n    data: {\n      employeeId,\n      decision,\n      result,\n      createdAt: new Date(),\n    },\n  });\n}\n```\n\nNow the employee has memory.\n\nNot necessarily memory as a giant conversation transcript.\n\nMemory as state and relationships.\n\nLet's walk through the entire workflow.\n\nSarah replies:\n\nSounds interesting. Follow up next Tuesday.\n\n```\nGmail\n  ↓\nemail.replied\nEmail\n  ↓\nrelated_to\n  ↓\nLead #123\nLead #123\n  ↓\nowned_by\n  ↓\nMaya\nMaya\n  ↓\nRead Graph\n  ↓\nUnderstand Context\n```\n\nSarah wants a follow-up next Tuesday.\n\n```\nTask\n  ↓\nscheduled_for\n  ↓\nTuesday 9:00 AM\n```\n\nMaya sleeps 💤\n\nTuesday arrives\n\n```\nScheduler\n  ↓\nfollowup.due\n  ↓\nWake Maya\nMaya\n  ↓\nLead #123\n  ↓\nSarah\n  ↓\nPrevious Conversation\nMaya\n  ↓\nsend_email()\n  ↓\nSarah\nTask #123\nstatus = completed\n\nEmail #43\nstatus = sent\n\nLead #123\nlast_contacted = today\n```\n\nThen:\n\n```\nMaya\n  ↓\nSleep\n```\n\nThat's a tiny AI employee.\n\nThe architecture is surprisingly simple:\n\n```\n                   ┌─────────────┐\n                   │    Events   │\n                   └──────┬──────┘\n                          ↓\n                   ┌─────────────┐\n                   │    Graph    │\n                   │             │\n                   │ State       │\n                   │ Relations   │\n                   │ History     │\n                   └──────┬──────┘\n                          ↓\n                   ┌─────────────┐\n                   │ AI Employee │\n                   └──────┬──────┘\n                          ↓\n                  ┌───────┴───────┐\n                  ↓               ↓\n                Tools         Scheduler\n                  │               │\n                  └───────┬───────┘\n                          ↓\n                        Events\n                          │\n                          └────→ Graph\n```\n\nThe important part is the final arrow:\n\n```\nAgent\n  ↓\nAction\n  ↓\nEvent\n  ↓\nGraph\n  ↓\nNext Decision\n```\n\nThe agent changes the world.\n\nThe graph records the change.\n\nThe next time the employee wakes up, it doesn't start over.\n\nIt continues.\n\nI think the future of AI employees looks less like:\n\n```\nPrompt → LLM → Tool\n```\n\nand more like:\n\n```\nWorld\n  ↓\nGraph\n  ↓\nAgent\n  ↓\nAction\n  ↓\nEvent\n  ↓\nGraph\n```\n\nThe LLM provides reasoning.\n\nThe tools provide capabilities.\n\nThe scheduler provides time.\n\nEvents provide wake-ups.\n\nThe graph provides continuity.\n\nThat's the interesting part.\n\nWe're not just building agents that can do things.\n\nWe're building software that can own work.\n\nThat's what [Roster](https://get-roster.com) is for.\n\nIf the same follow-ups, handoffs, and waiting loops keep eating your week, give them to an AI employee.", "url": "https://wpnews.pro/news/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent", "canonical_source": "https://dev.to/bobbyhalljr/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent-1098", "published_at": "2026-08-28 03:12:27+00:00", "updated_at": "2026-08-28 03:18:41.541592+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "developer-tools"], "entities": ["Roster", "Maya"], "alternates": {"html": "https://wpnews.pro/news/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent", "markdown": "https://wpnews.pro/news/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent.md", "text": "https://wpnews.pro/news/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent.txt", "jsonld": "https://wpnews.pro/news/how-to-build-an-ai-employee-with-a-knowledge-graph-not-just-another-agent.jsonld"}}