# Kinship Graph Workflow

Three worlds — Users, Agents, and Markets — converge in a single Apache AGE graph. At the centre sits the DUNA (Decentralized Unincorporated Nonprofit Association): a legal entity registered under West Virginia law. The DUNA is the real-world legal wrapper; the Market is its on-chain counterpart. Who referred whom, who owns what, how much was earned, what was voted on — all queryable from one place through relationship traversal.

### The Big Picture — Three Worlds, One Graph

User — registers, gets a —→ Wallet — enters a —→ Kinship Code — builds —→ Lineage Chain
User — creates —→ Presence (Avatar) — gives it —→ Knowledge + Prompt — adds —→ Worker + Tools
User — founds / joins —→ DUNA (legal entity, WV law) — becomes —→ Market (on-chain counterpart)
DUNA — BECAME —→ Market — has —→ Proposals — users —→ Vote / Trade / Contribute / Alliances
User — purchases —→ Offering — triggers —→ Lineage Rewards — flows up to —→ Ancestors
User asks a question → AI agent picks a tool → Graph traversal → Cypher query → Contextual answer
How Graph Traversal Works
From user question to graph-powered answer — the complete pipeline
When a user chats with their AI agent, the agent doesn't query the graph directly. Instead, it has 7 pre-built graph tools. The LLM decides which tool to call based on the user's question, the tool runs a scoped Cypher query, and the result feeds back into the LLM's response.

### End-to-End Pipeline

User sends message → POST /api/chat/stream
↓
Presence Agent (Supervisor LLM) — reads message, decides what to do
↓ picks a tool from its toolbox
Graph Tool — e.g. my_lineage(), my_rewards(), search_knowledge_graph()
↓ tool function runs
graph_retrieval.py — builds Cypher query with caller's wallet/ID baked in
↓ safety check
graph_guard.py — rejects unbounded paths, requires anchored queries, writes audit log
↓ execute
graph.py (AGE engine) — wraps Cypher in ag_catalog.cypher(), runs against PostgreSQL
↓ results flow back
Presence Agent receives structured text → weaves it into a natural language response → User sees answer
The 7 Graph Tools Available to Every Agent
How tools are given to agents When an agent is built (at factory.py), the system checks if graph is enabled. If yes, it creates 7 LangChain tools with the caller's wallet and KB IDs baked into closures — the LLM can never widen its own scope or access another user's data.
1. search_knowledge_graph(query) — Vector search + graph entity expansion. The query goes ONLY to pgvector; graph adds provenance (which agent owns this KB) and related entities.
2. my_graph_context() — Full neighbourhood: agents you own, DUNAs you belong to, markets you sponsor, your upline.
3. my_lineage() — Referral ancestry chain with tier labels (Genesis → Parent → GP → GGP → GGGP).
4. my_referrals() — Downline: people who used your kinship code to join.
5. my_usdc_purchases() — USDC purchase history (Stripe onramp sessions).
6. my_membership() — Subscription tier and status.
7. my_rewards() — Lineage rewards earned, with tier and claim status.
Security: Why the LLM Can't Break Out
Three layers of protection Layer 1 — Closure scoping: The user's wallet and KB IDs are captured when the tools are created. The LLM chooses WHICH tool to call, but cannot change the wallet it queries for. It can only see its own data.
Layer 2 — Query guard: Every Cypher query passes through graph_guard.py which rejects unbounded variable-length paths (preventing full-graph scans) and requires at least one literal anchor value (preventing unscoped queries like "MATCH (n) RETURN n").
Layer 3 — Audit log: Every graph query is logged with the caller identity, operation type, and query length — making any leakage or abuse traceable.
Traversal Examples
5 real scenarios — what the user asks, what the graph does
User: "Who referred me? Show my full referral chain."
Step 1: LLM reads the question, recognizes it's about referral ancestry, and calls the my_lineage() tool.
Step 2: The tool calls graph_retrieval.lineage_context(wallet) with the user's wallet already baked in from the closure.
Step 3: lineage_context builds and runs this Cypher query: MATCH (:Wallet {address: '7xK3..'})-[r:REFERRED_BY]->(anc:Wallet) RETURN {address: anc.address, tier: r.tier, pos: r.pos, is_genesis: anc.is_genesis} ORDER BY r.pos LIMIT 10
Step 4: Graph returns the chain: Your lineage (referral chain): - PARENT: 9aB4.. - GP: 3cD7.. - GGP: 1eF2.. - GGGP: 8gH5.. (Genesis)
Step 5: LLM receives this text and writes a natural response: "You were referred by wallet 9aB4 (your Parent). Their referrer was 3cD7 (Grandparent), going up to the Genesis wallet 8gH5."
User: "How much have I earned from referrals?"
Step 1: LLM calls the my_rewards() tool.
Step 2: The tool calls graph_retrieval.user_rewards_context(user_id). The user_id was captured from context_signals when the agent was built.
Step 3: Cypher query traverses EARNED edges: MATCH (u:User {id: '42'})-[e:EARNED]->(r:Reward) RETURN {tier: r.tier, amount: r.amount, status: r.status, claim_status: r.claim_status} LIMIT 15
Step 4: Graph returns and the function aggregates: Your lineage rewards (total $14.50): - PARENT: $8.00 (processed/claimable) - GP: $4.50 (processed/claimable) - GGP: $2.00 (pending/locked)
Step 5: LLM responds: "You've earned $14.50 total from referral rewards. $12.50 is claimable and $2.00 is still pending."
User: "Tell me about machine learning" (knowledge question)
Step 1: LLM calls search_knowledge_graph("machine learning").
Step 2: The tool does a hybrid search — two systems working together:
a) Vector search (pgvector): The query text is embedded into a 1024-dim vector using Voyage AI. pgvector finds the top 8 most similar chunks across all the agent's KBs.
b) Graph expansion: For each matching chunk, the graph traverses MENTIONS edges to find entities, then RELATED_TO edges to find connected entities. Also finds which other agents use the same KBs (provenance).
Step 3: Entity expansion Cypher: MATCH (c:Chunk)-[:MENTIONS]->(e:Entity) WHERE c.id IN ['chunk_a1', 'chunk_b2', 'chunk_c3'] AND e.kb_id IN ['kb_001'] OPTIONAL MATCH (e)-[:RELATED_TO]->(e2:Entity) RETURN {entity: e.name, related: e2.name} LIMIT 15
Step 4: Result combines text + graph context: Relevant knowledge: [chunk text about ML from the user's KB...] Key concepts in these results: - Neural Networks (related to: Deep Learning, Backpropagation) - Supervised Learning (related to: Classification, Regression) Related in the knowledge graph: - 'ML Handbook' is used by agent @my-assistant
Step 5: LLM has both the relevant text AND the entity context. It answers the ML question using the KB content, and can say things like "Based on your ML Handbook, neural networks are..." — grounded in the user's own knowledge, not generic training data.
User: "What agents do I own? What markets am I involved in?"
Step 1: LLM calls my_graph_context() — the broadest tool, returns the full neighbourhood.
Step 2: The function runs 4 separate Cypher queries in sequence, all anchored on the user's wallet: -- Query 1: Agents MATCH (:Wallet {address: '7xK3..'})<-[:OWNED_BY]-(a:Agent) RETURN {name: a.name, type: a.type, handle: a.handle} LIMIT 25 -- Query 2: DUNAs (Communities) MATCH (:Wallet {address: '7xK3..'})-[:MEMBER_OF]->(c:Context) RETURN {name: c.name} LIMIT 25 -- Query 3: Markets (inside DUNAs) MATCH (m:Market)-[:SPONSORED_BY]->(:Wallet {address: '7xK3..'}) RETURN {name: m.name, status: m.launch_status} LIMIT 25 -- Query 4: Upline MATCH (:Wallet {address: '7xK3..'})-[:REFERRED_BY]->(anc:Wallet) RETURN {ancestor: anc.address} LIMIT 25
Step 3: Results combined into one text block: Agents you own: - My Assistant (presence) @user-handle - My Bluesky Bot (worker) @user-bsky DUNAs you belong to: - My DUNA Markets you sponsor: - My DUNA Market [launched] Your lineage (upline): - 9aB4..
Step 4: LLM weaves this into a coherent overview of the user's entire platform presence.
User: "How many people did I refer?"
Step 1: LLM calls my_referrals().
Step 2: Cypher walks the REFERRED_BY edges in the reverse direction — instead of going UP the chain (who referred me), it goes DOWN (who did I refer): MATCH (d:Wallet)-[r:REFERRED_BY {tier: 'PARENT'}]->(:Wallet {address: '7xK3..'}) RETURN {address: d.address} LIMIT 20 The filter tier: 'PARENT' ensures only direct referrals are returned — not people 2 or 3 levels down.
Step 3: LLM responds: "You have 3 direct referrals: wallets 4xA2.., 8bC1.., and 2dE9.."
Identity & Membership
Who the user is, where they came from, and what tier they belong to
When a user registers, their wallet, referral code, subscription tier, and onboarding progress all become connected nodes in the graph — forming a complete identity picture.
1 Onboarding
What it is A 6-step wizard that every new user completes. They create a Presence (digital avatar), upload knowledge, set instructions, then create a Worker agent with tools. Each step's completion status is tracked: avatar → inform → instruct → worker → worker_inform → worker_instruct → complete.
Why we store it in the graph The AI agent can see whether a user is brand new or fully onboarded. This lets it tailor conversations — guiding new users through setup, while giving experienced users direct answers. It also enables platform analytics: how many users drop off at step 3, how many complete all 6 steps.
How it connects
User — HAS_STATUS → Event (records each status transition as a timestamped event node)
The User node also carries onboarding_step and onboarding_status as direct properties for quick lookup
2 Subscription
What it is The user's paid membership tier managed through Stripe. Tiers include Free, Pro, and Cofounder. Each subscription tracks the tier level, billing cycle (monthly or yearly), active/inactive status, and Stripe customer ID.
Why we store it in the graph The AI agent needs to know a user's membership level to provide appropriate responses. A Pro member asking about a premium feature gets a how-to guide; a Free member asking the same question gets an upgrade suggestion. It also enables queries like "show me all Pro members who also sponsor a market" — crossing identity and governance in one traversal.
How it connects
User — SUBSCRIBED → Subscription (tier, status, billing cycle)
3 Lineage
What it is The referral ancestry chain. When a user registers using someone's Kinship Code, that person becomes their Parent. The Parent's referrer becomes the Grandparent, and so on — up to 5 levels deep. Each level has a named tier: Genesis (the root), Parent, Grandparent (GP), Great-Grandparent (GGP), and Great-Great-Grandparent (GGGP).
Why we store it in the graph Lineage is the economic backbone of the platform. When a purchase happens, rewards are distributed upward through the lineage chain — each ancestor receives a tier-appropriate percentage. A graph makes this traversal natural: walk the REFERRED_BY edges upward, and at each stop you know the tier and can calculate the reward.
How it connects
Wallet — REFERRED_BY (tier: PARENT, pos: 1) → Wallet (direct referrer)
Wallet — REFERRED_BY (tier: GP, pos: 2) → Wallet (referrer's referrer)
... continues up to 5 levels, ending at Wallet (is_genesis: true)
4 Connections
What it is User-to-user social links — like friend requests. One user sends a connection request to another, and it has a status (pending, accepted, rejected). Unlike lineage (which is economic — who referred whom), connections are social (who chose to connect with whom). Two completely different relationship types that together give a much richer picture of user relationships.
Why we store it in the graph Social graph is the classic use case for graph databases. "Who knows who", "mutual connections", and "2nd-degree connections" are multi-hop queries that are painful in SQL but trivial in a graph. More importantly, connections amplify every other item: "show me markets my connections are participating in" (social + governance), "which of my connections also activated this bot?" (social + agents), "what offerings are popular among my connections?" (social + commerce). The social layer turns isolated data points into a network.
How it connects
Wallet (sender) — CONNECTED → Wallet (receiver) — with status (pending / accepted / rejected)
This creates a second social layer alongside lineage:
REFERRED_BY = economic relationship (who invited whom, controls reward flow)
CONNECTED = social relationship (who chose to connect, enables recommendations)
Agent World
The AI agent ecosystem — who created what, with what capabilities
Every user has a Presence (supervisor agent) that can have multiple Workers beneath it. Each agent is equipped with knowledge bases, instruction prompts, and external tools — all represented as connected nodes.
5 Agents List (Presence)
What it is The Presence agent is the user's primary digital avatar and supervisor. It has a name, a unique handle (like @alex), a description, a personality tone, and a tagline. The Presence makes high-level decisions and delegates specific tasks to its Worker agents.
Why we store it in the graph The graph answers ownership and relationship questions instantly. "Which agents does this wallet own?" — follow the OWNED_BY edge. "Do these two agents share an owner?" — check if their OWNED_BY edges point to the same wallet. "How many agents exist in this DUNA?" — traverse IN_CONTEXT edges. This also powers agent discovery and recommendation across the platform.
How it connects
Agent — OWNED_BY → Wallet (the creator's wallet)
Agent — IN_CONTEXT → DUNA (the Duna it belongs to)
Agent — HAS_PRESENCE → DUNA (its community presence role)
6 Workers List
What it is Worker agents are the hands of the Presence. Each Worker is specialized for a specific task — posting on Bluesky, sending Gmail, managing Google Calendar, messaging on Telegram. A single Presence can have multiple Workers, typically one per external tool.
Why we store it in the graph The supervisor-worker hierarchy is a natural graph structure. By traversing REPORTS_TO edges, the system can answer "what are all the capabilities of this Presence?" (by finding all its workers and their tools). If a worker fails, the graph helps identify alternative workers with similar capabilities.
How it connects
Worker Agent — REPORTS_TO → Presence Agent (its supervisor)
Worker Agent — OWNED_BY → Wallet (same owner as the Presence)
7 Inform (Knowledge Bases)
What it is An agent's knowledge — the documents, PDFs, and text that give it domain expertise. When content is uploaded, it gets split into chunks, each chunk gets a vector embedding (for similarity search), and an LLM extracts named entities and their relationships from the text. This creates a rich content graph beneath each knowledge base.
Why we store it in the graph Vector search alone tells you "this text is relevant." The graph adds provenance and context: "this knowledge belongs to agent X, which is owned by wallet Y, and the same KB is also used by agents Z and W." Entity extraction adds another layer — when a user asks about a concept, the graph expands beyond the matching chunks to show related entities. This is the hybrid search approach: vector finds the text, graph provides the context.
How it connects
Agent — USES_KB → KnowledgeBase
KnowledgeBase — HAS_DOCUMENT → Document — HAS_CHUNK → Chunk
Chunk — MENTIONS → Entity — RELATED_TO → Entity
Chunk — NEXT → Chunk (preserves reading order for sequential context)
8 Instruct (Prompts)
What it is The agent's personality and behavioral instructions. The user describes a goal in plain language, and the system generates a full system prompt — defining how the agent should behave, what tone to use, what to avoid, and what its purpose is.
Why we store it in the graph Storing prompts in the graph enables behavioral analysis and auditing. "What instructions is this agent following?" is a single edge traversal. It also enables grouping agents with similar instructions and recommending prompt templates based on what works well for similar agents.
How it connects
Agent — USES_PROMPT → Prompt (contains name, goal text, and full system instructions)
9 Tools
What it is External service connections that give agents the ability to act in the real world. Currently supported: Bluesky (post, DM, follow), Gmail (send, read), Google Calendar (create events), Google Meet (create meetings), Telegram (send messages), and Solana (transfer tokens).
Why we store it in the graph The graph maps capabilities to agents. "What can this agent do?" — traverse its USES_TOOL edges. "Which users have Bluesky connected?" — find all ToolAccount nodes linked to the Bluesky Tool node. This enables capability-based agent matching and platform-wide integration analytics.
How it connects
Agent — USES_TOOL → ToolAccount — OF_TOOL → Tool (Bluesky, Gmail, Calendar, Telegram, Solana)
DUNA Layer
DUNA — the legal wrapper that gives on-chain governance real-world standing
A DUNA (Decentralized Unincorporated Nonprofit Association) is a legal entity registered under West Virginia law. It is the legal foundation beneath a Market — the real-world entity at the Secretary of State, while the Market is its on-chain counterpart. Without a DUNA, there is no Market.
10 DUNA
What it is A DUNA (Decentralized Unincorporated Nonprofit Association) is a legal entity registered under West Virginia law. In the Kinship platform, a DUNA is the legal foundation beneath a Market — the real-world entity at the Secretary of State, while the Market is its on-chain counterpart.
We store DUNA details, member list, member roles and permissions, founder/owner, membership history (join/leave), invitations, and the relationships between users and DUNAs. A user can be a member of multiple DUNAs, and each DUNA can host its own Market once it meets the membership threshold and receives government approval.
Why we store it in the graph The AI agent can answer: "What DUNAs do I belong to?", "How many members does this DUNA have?", "Who founded this DUNA?", "What role do I have?", and "Which of my connections are also members of this DUNA?" It also enables cross-layer queries like "Show me all DUNAs where I'm a member that also have an active Market" — crossing the legal and governance layers in a single traversal.
How it connects
DUNA — FOUNDED_BY → Wallet (the founder)
Wallet — MEMBER_OF → DUNA (role, joined_at, method)
Code — GRANTS_ACCESS_TO → DUNA (invitation codes)
DUNA — BECAME → Market (links legal entity to on-chain entity)
Commerce & Rewards
Buying, earning, and growing — the platform's economic engine
When a user buys an offering, it creates a chain reaction: the purchase is recorded, lineage rewards are calculated and distributed to ancestors, and each reward links back to the originating purchase for full traceability.
11 User Purchased Offerings
What it is Creators on the platform can sell offerings — digital products, services, or access passes. Users purchase these with USDC (a stablecoin). Each purchase records the buyer, the offering, and the amount paid.
Why we store it in the graph A purchase is not an isolated event — it triggers a chain reaction through the lineage system. The graph can trace the full lifecycle: "this purchase was made by user A, which triggered rewards for users B (Parent), C (GP), and D (GGP)." The AI agent can answer "show me my purchase history" or "which offerings are most popular among my referrals" through simple edge traversals.
How it connects
User (buyer) — TRIGGERED_BY ← Purchase — OF_OFFERING → Offering (the product)
Offering — OWNED_BY → Wallet (the creator who listed it)
12 Rewards
What it is Lineage rewards are the economic incentive for referrals. When a purchase occurs, the system walks up the buyer's lineage chain and assigns a reward to each ancestor based on their tier. The Parent gets the highest percentage, the Grandparent gets less, and so on. Each reward tracks its tier, dollar amount, processing status (pending/processed), and claim status (locked/claimable/claimed).
Why we store it in the graph Rewards tie together purchases and lineage — two separate parts of the graph. By storing rewards as nodes connected to both the earning user and the originating purchase, the graph enables full-circle queries: "how much have I earned total?", "which purchases generated my rewards?", "what's my pending vs. claimed balance?"
How it connects
User — EARNED → Reward (tier, amount, status, claim_status)
Reward — FOR_PURCHASE → Purchase (the purchase that triggered this reward)
The full chain: a Purchase happens → the system traverses the buyer's lineage (REFERRED_BY edges) → creates a Reward node for each ancestor → each Reward links back to the originating Purchase.
Governance & Markets
Markets, voting, and alliances — the on-chain counterpart of a DUNA
A Market is the on-chain governance entity that a DUNA becomes. Once a DUNA is registered and approved, its Market is created — and within it, users define objectives, submit proposals, vote with real stakes, form alliances, and contribute USDC. The full lifecycle of decentralized governance, anchored to its parent DUNA.
13 User Created Markets
What it is A Market is the on-chain governance counterpart of a DUNA. When a DUNA (the legal entity at the Secretary of State) is ready to go on-chain, it becomes a Market — linked by the BECAME relationship. The sponsor defines its governance structure: each market has Objectives (high-level goals), and each objective has Dimensions (measurable criteria with weight percentages). Operators are AI agents assigned to pursue specific objectives within a market.
DUNA → Market: The DUNA is the legal foundation; the Market is its on-chain expression. One DUNA, one Market.
Why we store it in the graph Governance structures are deeply hierarchical and relational. The full chain is: DUNA — BECAME → Market → Objectives → Proposals → Votes/Trades. "What markets does this user sponsor?" is one edge hop. "What objectives does this market have, and which AI agents are operating on them?" is a two-hop traversal. "Which DUNA does this market come from, and how many members does it have?" connects governance back to the legal entity. In a relational database, answering "show me all users connected to this market through any role — sponsor, voter, operator, or alliance member" requires joining 6+ tables. In the graph, it is a single neighbourhood query.
How it connects
DUNA — BECAME → Market (legal entity becomes on-chain entity)
Market — SPONSORED_BY → Wallet (the creator/sponsor)
Objective — IN_MARKET → Market
Dimension — OF_OBJECTIVE → Objective (with weight percentage)
Operator — OPERATES_IN → Market and IS_AGENT → Agent
Market — PRIMARY_OPERATOR → Operator (the lead AI agent)
14 User Voted Markets
What it is Two types of voting exist. Electors are appointed participants who trade on proposals with real USDC stakes — they pick a side (FOR or AGAINST) and commit money behind their position. Citizens are any wallet holders who cast simple directional votes without financial stakes.
Why we store it in the graph Voting creates a web of opinions across users and proposals. The graph enables pattern analysis: "who voted the same way as me?" (find shared VOTED edges). "What is this user's voting history across all markets?" (traverse all their edges). "Is there a voting bloc — wallets that consistently vote together?" (community detection). This transparency is fundamental to democratic accountability.
How it connects
Elector — TRADED → Proposal (side: FOR/AGAINST, stake amount in USDC)
Wallet — VOTED → Proposal (side: FOR/AGAINST)
Proposal — IN_MARKET → Market
Proposal — AUTHORED ← Wallet (who submitted the proposal)
15 Recent Contributions
What it is Financial contributions to markets. During a token launch, users commit USDC to back the market. Each contribution records the wallet, the target market, the amount committed, and the status (committed, claimed, or refunded).
Why we store it in the graph Contributions connect wallets to markets through financial participation. The graph answers: "how much total funding has this market raised?" (aggregate all CONTRIBUTED edges), "what is this user's investment portfolio across all markets?" (traverse all their CONTRIBUTED edges), and "who are the biggest backers?" (sort by amount).
How it connects
Wallet — CONTRIBUTED → Market (amount, status, role)
Wallet — COMMITTED_USDC → Commitment (real-time event with tx signature)
16 Alliances
What it is Sub-groups within markets. Users form alliances to collaborate on shared goals. Each alliance has a name, a handle, a creator, and a status. Members join with specific roles (admin or member) and may be designated as signers for the alliance's FROST threshold wallet — meaning they are required participants in multi-signature transactions.
Why we store it in the graph Alliances create a sub-group layer within the market hierarchy. The graph reveals: "what alliances exist in this market?" (INSIDE edges), "which users are in multiple alliances?" (wallets with multiple TEAM_MEMBER edges), and "who are the signers for this alliance's treasury?" (filter by is_signer).
How it connects
Alliance — INSIDE → Market (the parent market)
Wallet — TEAM_MEMBER → Alliance (role: admin/member, is_signer: true/false)
Alliance — CREATED_BY → Wallet (the alliance creator)
17 Activated Bots
What it is Users can activate bots created by other users. Unlike agents that a user creates and owns, activated bots are third-party creations that the user has chosen to use. The activation links the using user to the bot, while the bot itself tracks its original creator.
Why we store it in the graph This creates a marketplace dynamic. Bot creators can see adoption: "how many users activated my bot?" (count ACTIVATED edges). Users discover popular bots: "what bots do people in my DUNA use?" (traverse DUNA → members → ACTIVATED). Platform analytics can identify the most-activated bots for recommendations.
How it connects
User — ACTIVATED → Agent (the bot they chose to use)
Bot — CAME_FROM → Wallet (the original creator's wallet)
Not Yet in Graph
Wallet balances, transactions, and action logs — not yet in graph
These two items have no existing graph node types or Cypher builders.
18 Wallet Balance / Transactions
What it is The SOL and USDC balance of a user's Solana wallet, plus their transaction history — transfers sent, received, token swaps, and program interactions.
Why it's not built yet Balances and transactions live on the Solana blockchain, not in any local database. The Wallet node exists in the graph (storing the address), but it has no balance properties and there is no Transaction node type. This would need: an external data source (Solana RPC or an indexer like Helius), a periodic fetch mechanism, node types, and Cypher builders.
If built, it would connect like this
Wallet would gain properties: sol_balance, usdc_balance, last_synced
Wallet — SENT / RECEIVED → Transaction (amount, token, signature, timestamp)
19 Action Count / Action List
What it is A log of every time a skill (automation) fires. Each execution records which skill ran, when it was triggered, whether it succeeded or failed, the result or error message, and the trigger data.
Why it's not built yet The data exists — the skill_executions table logs every fire with all the details. However, no graph representation was built for it. This is likely intentional: skill executions are high-volume, and projecting all of them into the graph could create noise. A sensible approach would be to project aggregated summaries or only the most recent N executions per skill.
If built, it would connect like this
Skill — EXECUTED → SkillExecution (triggered_at, success, result summary)
SkillExecution — RAN_BY → Agent (the agent whose skill it was)
Graph Structure
Single User's Complete Node Tree
Every node and relationship radiating from one user's Wallet — the full shape of a user's presence in the graph. Note how Market is the on-chain counterpart of a DUNA (BECAME), not a standalone entity.

### User → Wallet → DUNA → Market → Everything

- User — identified by →
  - Wallet
    - Lineage REFERRED_BY
      - Parent Wallet tier: PARENT, pos: 1
      - Grandparent Wallet tier: GP, pos: 2
      - Great-Grandparent Wallet tier: GGP, pos: 3
      - Genesis Wallet is_genesis: true
    - Kinship Code OWNS_CODE
    - Subscription SUBSCRIBED — tier, status, billing
    - Connected Wallets CONNECTED — status: pending / accepted
    - Linked Wallets LINKED_WALLET
    - Presence Agent OWNED_BY ← Agent
      - Knowledge Base USES_KB
        - Document HAS_DOCUMENT
          - Chunk HAS_CHUNK
            - Entity MENTIONS → RELATED_TO → Entity
            - Next Chunk NEXT (reading order)
      - Prompt USES_PROMPT — goal, system instructions
      - Worker Agent REPORTS_TO
        - Tool Account USES_TOOL
          - Tool OF_TOOL — Bluesky, Gmail, Calendar, Telegram, Solana
        - Knowledge Base USES_KB
        - Prompt USES_PROMPT
    - Activated Bot ACTIVATED
      - Bot Creator Wallet CAME_FROM
    - DUNA (Legal Entity) MEMBER_OF — role, joined_at, method
      - Founder Wallet FOUNDED_BY
      - Invitation Code GRANTS_ACCESS_TO
      - Market BECAME — legal entity → on-chain entity
        - Objective IN_MARKET
          - Dimension OF_OBJECTIVE — weight_pct
          - Operator OPERATES_IN — IS_AGENT → Agent
        - Proposal IN_MARKET
          - Trade TRADED — side, stake_usd
          - Citizen Vote VOTED — side: FOR / AGAINST
        - Contribution CONTRIBUTED — amount, status
        - Market Member JOINED — role
        - Alliance INSIDE
          - Alliance Member TEAM_MEMBER — role, is_signer
    - Offering OWNED_BY (as creator)
      - Purchase OF_OFFERING ← TRIGGERED_BY
        - Reward FOR_PURCHASE — flows to ancestors via EARNED
    - Rewards Earned EARNED — tier, amount, status, claim_status
    - Onramp Session PURCHASED_USDC — Stripe onramp

Full Picture
How Everything Connects — One User's Complete Graph

### Example: A user joins the platform, builds agents, founds a DUNA, and participates in governance

STEP 1 — JOINS THE PLATFORM
User A → identified by → Wallet: 7xK3... → referred by → User B (PARENT) → referred by → User C (GP) → ... → Genesis
User A → subscribed to → Pro Tier (active, monthly) → owns code → KIN-A42 → connected to → User D, User E
STEP 2 — BUILDS AGENTS (ONBOARDING)
Wallet: 7xK3... ← owned by ← Presence: @user-handle → uses KB → Product Docs (KB) → uses prompt → "Friendly Helper"
Worker: @user-bsky → reports to → Presence: @user-handle → uses tool → Bluesky Account
STEP 3 — FOUNDS / JOINS A DUNA (LEGAL ENTITY)
Wallet: 7xK3... → founds → DUNA (registered under WV law) ← members join via invitation codes
STEP 4 — DUNA BECOMES A MARKET (ON-CHAIN)
DUNA — BECAME → Market (on-chain counterpart) → has → 3 Proposals
Wallet: 7xK3... → voted FOR → Proposal: "Add NFT Tier" → contributed → Market (500 USDC)
Wallet: 7xK3... → team member → Alliance: "Core Builders" → inside → My DUNA Market
STEP 5 — EARNS FROM THE NETWORK
User D → referred by User A → → purchases → Offering ($20)
User D's Purchase → triggers reward → User A earns $2 (PARENT tier) → also triggers → User B earns $1 (GP tier)
STEP 6 — ASKS THE AI AGENT A QUESTION
User A: "How much have I earned?" → Agent calls my_rewards() → Graph traverses EARNED edges → "You've earned $14.50 total"
Why a graph instead of SQL joins?
All of this data already lives in 3 PostgreSQL databases. The graph doesn't replace them — it's a derived projection (the relational tables remain the source of truth). The graph adds value because:
• Relationships are first-class. In SQL, relationships are implicit (foreign keys, JOINs). In the graph, every relationship is an explicit, named, queryable edge with its own properties.
• Multi-hop queries are natural. "Find me users who are in the same DUNA and also voted the same way on a proposal" is a multi-hop traversal in the graph. In SQL, it's a self-join nightmare.
• Cross-database queries disappear. Agent data (kinship_agent), user data (kiduna_backend), and market data (kinship_markets) live in separate databases. The graph unifies them — one query touches all three worlds.
• AI agents need context, not rows. An LLM doesn't want a ResultSet; it wants "here are your agents, DUNAs, lineage, and recent rewards." The graph's text-oriented retrieval functions give the LLM exactly that.
• The DUNA→Market hierarchy is natural. "Which Market did this DUNA become? How many members does the DUNA have? Who founded it?" — these structural questions map directly to graph traversal, not to cross-table JOINs.