Skip to main content
Glama
README.md
# KnowledgeOps AI

A Laravel knowledge assistant that combines cited RAG answers, an MCP server, and a guarded agent workflow. The agent can propose a support ticket, but it cannot execute the tool until a human approves the stored action.

## Why this project

Many AI demos stop at a chat box. KnowledgeOps AI demonstrates the backend concerns needed for a safer production system:

- workspace-scoped document ingestion and retrieval;
- deterministic local embeddings for a zero-cost demo;
- optional OpenAI embeddings and generated answers;
- PostgreSQL with pgvector search and an SQLite fallback;
- JSON-RPC MCP tools with typed input schemas;
- human approval before state-changing agent actions;
- queues, audit records, API-key protection, and automated tests.

## Architecture

```mermaid
flowchart LR
    Client[API or MCP client] --> Laravel[Laravel API]
    Laravel --> Ingest[Queued ingestion]
    Ingest --> Chunk[Chunk + embed]
    Chunk --> Vector[(PostgreSQL + pgvector)]
    Laravel --> Retrieve[Hybrid retrieval]
    Retrieve --> Vector
    Retrieve --> LLM[LLM or local fallback]
    LLM --> Answer[Cited answer]
    Answer --> Agent[Guarded agent]
    Agent --> Pending[(Pending action)]
    Pending --> Approval{Human approval}
    Approval -->|approved| MCP[MCP tool registry]
    MCP --> Ticket[(Support ticket)]
```

## Stack

- PHP 8.3 and Laravel 13
- OpenAI Responses and Embeddings APIs, or a local deterministic fallback
- PostgreSQL 17 with pgvector; SQLite is supported for quick local development
- Redis queues and cache in Docker
- MCP-compatible JSON-RPC endpoint
- PHPUnit feature and unit tests

## Quick start with SQLite

```bash
cp .env.example .env
composer install
php artisan key:generate
touch database/database.sqlite
php artisan migrate --seed
php artisan serve
```

Open [http://localhost:8000](http://localhost:8000). The default API key is `local-demo-key`.

The local provider needs no external service. To use OpenAI, update `.env`:

```dotenv
AI_PROVIDER=openai
OPENAI_API_KEY=your-key
OPENAI_CHAT_MODEL=gpt-4.1-mini
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
```

Never commit the real `.env` file.

## Docker with pgvector and Redis

```bash
docker compose up -d postgres redis
docker compose run --rm app php artisan migrate --seed
docker compose up -d app worker
```

The Docker environment enables pgvector retrieval and runs ingestion through Redis.

## API walkthrough

All API requests accept `X-API-Key: local-demo-key`.

### 1. Ingest a document

```bash
curl -X POST http://localhost:8000/api/documents \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-demo-key" \
  -d '{
    "workspace_id": "demo",
    "title": "Remote Work Policy",
    "source": "handbook://remote-work",
    "content": "Employees may work remotely three days per week. Manager approval is required for fully remote arrangements."
  }'
```

### 2. Ask a cited RAG question

```bash
curl -X POST http://localhost:8000/api/rag/ask \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-demo-key" \
  -d '{"workspace_id":"demo","question":"How many remote days are allowed?"}'
```

The response contains an answer plus source labels, document IDs, excerpts, and retrieval scores.

### 3. Run the agent

```bash
curl -X POST http://localhost:8000/api/agent/run \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-demo-key" \
  -d '{"workspace_id":"demo","question":"Create a ticket for a company-wide payment outage"}'
```

The agent returns `requires_approval: true` and stores a pending action. It does not create a ticket yet.

### 4. Approve the proposed action

```bash
curl -X POST http://localhost:8000/api/agent/actions/1/approve \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-demo-key" \
  -d '{"workspace_id":"demo"}'
```

Approval is single-use. A repeated approval returns HTTP 409 and cannot create a duplicate ticket.

## MCP endpoint

The MCP endpoint is `POST /api/mcp`. It supports `initialize`, `ping`, `tools/list`, and `tools/call`.

```bash
curl -X POST http://localhost:8000/api/mcp \
  -H "Content-Type: application/json" \
  -H "X-API-Key: local-demo-key" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

Available tools:

- `knowledge_search` searches only within the supplied workspace.
- `support_ticket_create` requires an explicit approved flag. The built-in agent supplies it only after the approval endpoint locks and updates a pending action.

## Tests and code style

```bash
php artisan test
./vendor/bin/pint --test
```

The suite covers API-key protection, ingestion, workspace isolation, cited retrieval, MCP discovery and calls, and the approval-based ticket workflow.

## Repository layout

```text
app/
├── Http/Controllers       API and MCP transport
├── Jobs                   queued document ingestion
├── Models                 documents, chunks, actions, tickets
└── Services
    ├── Ai                 chunking, embeddings, retrieval, RAG, agent
    └── Mcp                tool definitions and execution
database/
├── migrations             workspace-scoped schema and pgvector setup
└── seeders                runnable support-handbook example
```

## Push to GitHub

```bash
git init
git add .
git commit -m "Build KnowledgeOps AI Laravel RAG and MCP agent"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/knowledgeops-ai.git
git push -u origin main
```

Create the empty `knowledgeops-ai` repository in your GitHub account before the last two commands.

## Deliberate safety choices

- Workspace ID is applied to every retrieval and action query.
- The LLM receives retrieved passages, not unrestricted database access.
- State-changing tools require approval, which is recorded and locked in a transaction.
- Tool inputs are validated again at execution time.
- Local mode makes tests deterministic and prevents accidental external AI calls.

## License

MIT