Agent Resource Platform - this is an exploration into what a backbone for human-agent interaction in a business context might look like.

david 7151d949cf add workflow commands to arp_cli před 7 hodinami
arp_agent 7151d949cf add workflow commands to arp_cli před 7 hodinami
arp_cli 7151d949cf add workflow commands to arp_cli před 7 hodinami
auth 46993daca6 initial commit před 1 týdnem
graph e7c1121f4d add workflows před 7 hodinami
logging 7b1d31feba require auth for all operations, use db_bootstrap.sql script, remove redundant tests před 1 týdnem
mcp e7c1121f4d add workflows před 7 hodinami
models e7c1121f4d add workflows před 7 hodinami
workflow e7c1121f4d add workflows před 7 hodinami
.gitignore e7c1121f4d add workflows před 7 hodinami
CLIENT_GUIDE.md e7c1121f4d add workflows před 7 hodinami
README.md e7c1121f4d add workflows před 7 hodinami
go.mod 6bb7cea6b2 implement subscriptions with event filtering před 1 týdnem
go.sum 6bb7cea6b2 implement subscriptions with event filtering před 1 týdnem
gqlgen.yml 46993daca6 initial commit před 1 týdnem
init_prod.sql e7c1121f4d add workflows před 7 hodinami
server.go e7c1121f4d add workflows před 7 hodinami

README.md

ARP - Agent Resource Platform

A GraphQL-based coordination system for users and agents to collaborate on services, tasks, and workflows.

Overview

ARP (Agent Resource Platform) is a coordination backend that enables human users and AI agents to work together on shared services. It provides:

  • User Management - Role-based access control with fine-grained permissions
  • Service Coordination - Create and manage services with multiple participants
  • Task Management - Assignable work items with status tracking
  • Notes - Attach notes to services for context
  • Messaging - Real-time chat channels between participants
  • Workflow Engine - DAG-based workflow definitions with automatic task creation and dependency management

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      GraphQL API                            │
│  (gqlgen - schema-first, type-safe resolvers)               │
├─────────────────────────────────────────────────────────────┤
│                    Auth Middleware                          │
│  (JWT tokens, permission checks)                            │
├─────────────────────────────────────────────────────────────┤
│                     GORM Models                             │
│  User → Role → Permission                                   │
│  Service → Task → TaskStatus                                │
│  Channel → Message                                          │
│  Note                                                       │
├─────────────────────────────────────────────────────────────┤
│                   SQLite Database                           │
│  (arp.db - can be swapped for PostgreSQL/MySQL)             │
└─────────────────────────────────────────────────────────────┘

Quick Start

Prerequisites

  • Go 1.21+
  • SQLite3 (or modify for PostgreSQL/MySQL)

Running the Server

# Clone and run
go run server.go

# Server starts on http://localhost:8080

Running Tests

go test ./... -v

API Interaction with Bash

1. Start the Server

go run server.go &
# Server runs on http://localhost:8080

2. Inspect the GraphQL Schema

Use GraphQL introspection to discover the API schema:

# Get all types in the schema
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name kind description fields { name type { name kind ofType { name } } } } } }"}' | jq

# Get all queries and mutations
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { fields { name description } } mutationType { fields { name description } } } }"}' | jq

3. Initialize Database with Seed Data

Run the SQL bootstrap script to create permissions, roles, task statuses, and an admin user:

# Initialize the database with seed data
sqlite3 arp.db < init.sql

# Verify the data was created
sqlite3 arp.db "SELECT name FROM roles;"
# Output:
# admin
# manager
# user

sqlite3 arp.db "SELECT email FROM users;"
# Output:
# admin@example.com

The init.sql script creates:

  • 36 permissions covering all CRUD operations for each entity type
  • 3 roles: admin (full access), manager (service/task management), user (read-only + notes/messages)
  • 1 admin user with email admin@example.com and password secret123
  • 6 task statuses: open, in_progress, blocked, review, done, cancelled

4. Login and Get JWT Token

# Login to get JWT token
TOKEN=$(curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -d '{"query":"mutation { login(email: \"admin@example.com\", password: \"secret123\") { token user { email roles { name } } } }"}' | jq -r '.data.login.token')

echo "Token: $TOKEN"

5. Pull List of Services (Authenticated)

# Get all services with authentication
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"{ services { id name description createdAt participants { email } tasks { title status { label } } } }"}' | jq

6. Create a Service

# Create a new service
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"mutation { createService(input: {name: \"Project Alpha\", description: \"New project\", createdById: \"1\", participants: [\"1\"]}) { id name } }"}' | jq

7. Query Single Service by ID

# Get a specific service
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"{ service(id: \"1\") { id name description createdBy { email } participants { email } tasks { id title priority status { code label } } } }"}' | jq

Authentication & Authorization

Permission System

The system uses a hierarchical permission model:

User ─┬─ has many ─→ Role ─┬─ has many ─→ Permission
      │                    │
      └─ e.g., "admin"     └─ e.g., "service:create"

Required Permissions for Operations

Operation Required Permission
Update User user:update
Delete User user:delete
Update Task task:update
Delete Task task:delete
Update Note note:update
Delete Note note:delete
Update Service service:update
Delete Service service:delete
... ...

Using Authentication in Requests

# Include JWT token in Authorization header
curl -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"query":"..."}'

GraphQL Schema Overview

Core Types

  • User - Agent or human account
  • Role - Groups of permissions
  • Permission - Fine-grained access control (e.g., task:create)
  • Service - Coordination unit with participants and tasks
  • Task - Assignable work item with status
  • TaskStatus - Workflow states (open, in_progress, done)
  • Note - Notes attached to services
  • Channel - Chat between participants
  • Message - Individual chat messages

Key Queries

type Query {
  users: [User!]!
  user(id: ID!): User
  services: [Service!]!
  service(id: ID!): Service
  tasks: [Task!]!
  task(id: ID!): Task
  roles: [Role!]!
  permissions: [Permission!]!
  # ... more queries
}

Key Mutations

type Mutation {
  login(email: String!, password: String!): AuthPayload!
  createUser(input: NewUser!): User!
  createService(input: NewService!): Service!
  createTask(input: NewTask!): Task!
  # ... more mutations
}

Workflow Engine

The workflow engine enables you to define complex multi-step processes as JSON-based DAGs (Directed Acyclic Graphs). Each node in the DAG represents a task or decision point, and dependencies between nodes are automatically resolved.

Workflow Definition Format

Workflows are defined as JSON with a nodes object where each key is a unique node identifier:

{
  "nodes": {
    "start": {
      "type": "task",
      "title": "Initial Review",
      "content": "Review the initial request",
      "assignee": "1",
      "dependsOn": []
    },
    "analysis": {
      "type": "task",
      "title": "Data Analysis",
      "content": "Analyze the data",
      "assignee": "2",
      "dependsOn": ["start"]
    },
    "approval": {
      "type": "task",
      "title": "Manager Approval",
      "content": "Get manager approval",
      "assignee": "3",
      "dependsOn": ["analysis"]
    },
    "end": {
      "type": "task",
      "title": "Complete",
      "content": "Mark workflow as complete",
      "assignee": "1",
      "dependsOn": ["approval"]
    }
  }
}

Workflow Permissions

Operation Required Permission
Create Workflow Template workflow:create
Update Workflow Template workflow:manage
Delete Workflow Template workflow:manage
Start Workflow workflow:start
Cancel Workflow workflow:manage
Retry Node workflow:intervene
View Workflows workflow:view

Workflow Node Types

Type Description
task Creates a task for a user to complete
condition Evaluates conditions to determine next steps
parallel Spawns multiple concurrent branches
join Waits for multiple branches to complete
trigger Starts the workflow automatically

Automatic Task Completion Integration

When a task associated with a workflow node is marked as "done", the workflow engine automatically:

  1. Marks the corresponding node as completed
  2. Evaluates downstream dependencies
  3. Creates tasks for newly ready nodes

This enables workflows to progress automatically as users complete their assigned tasks.

Workflow API Examples

# Create a workflow template
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "mutation { createWorkflowTemplate(input: {name: \"Onboarding\", description: \"New employee onboarding\", definition: \"{\\\"nodes\\\":{\\\"start\\\":{\\\"type\\\":\\\"task\\\",\\\"title\\\":\\\"Welcome\\\",\\\"content\\\":\\\"Send welcome email\\\",\\\"assignee\\\":\\\"1\\\",\\\"dependsOn\\\":[]}}}\"}) { id name }"
  }' | jq

# Start a workflow instance
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "mutation { startWorkflow(templateId: \"1\", input: {serviceId: \"1\", context: \"New hire onboarding\"}) { id status template { name } } }"
  }' | jq

# Get all workflow instances
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"{ workflowInstances { id status template { name } service { name } } }"}' | jq

# Retry a failed workflow node
curl -s -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query":"mutation { retryWorkflowNode(nodeId: \"1\") { id nodeKey status retryCount } }"}' | jq

Environment Variables

Variable Default Description
JWT_SECRET your-secret-key-change-in-production Secret for JWT signing