text-to-cypher 0.1.17

A library and REST API for translating natural language text to Cypher queries using AI models
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
# Text to Cypher

[![build](https://github.com/FalkorDB/text-to-cypher/actions/workflows/build.yml/badge.svg)](https://github.com/FalkorDB/text-to-cypher/actions/workflows/build.yml)

A high-performance Rust library and API service that translates natural language text to Cypher queries for graph databases, featuring integration with genai and FalkorDB. Use as a library in your Rust applications or deploy the all-in-one Docker solution with integrated FalkorDB database, web browser interface, text-to-cypher API, and Model Context Protocol (MCP) server support!

## ✨ What's New

**Dynamic Cypher Skills**: Load FalkorDB-specific Cypher best practices at runtime from external skill files. The LLM can request detailed skill content on-demand via tool calling, keeping prompts compact while enabling deep expertise when needed. See [Dynamic Cypher Skills](#dynamic-cypher-skills) for details.

**Library Support**: Now available as a Rust library! Use text-to-cypher directly in your Rust applications without the REST API overhead.

**All-in-One Docker Solution**: Our Docker image includes everything you need in a single container:

- 🗄️ **FalkorDB Database** (port 6379) - Full graph database with Redis protocol
- 🌐 **FalkorDB Web Interface** (port 3000) - Interactive graph browser and query builder  
- 🚀 **Text-to-Cypher API** (port 8080) - Natural language to Cypher conversion
- 🤖 **MCP Server** (port 3001) - AI assistant integration support

## Features

### Core Capabilities
- **Text to Cypher Translation**: Convert natural language queries to Cypher database queries using AI
- **Enhanced Schema Discovery**: Automatically discover and analyze graph database schemas with example values
- **Query Validation**: Built-in validation system to catch syntax errors before execution
- **Self-Healing Queries**: Automatic retry with error feedback when queries fail
- **Library & API Modes**: Use as a Rust library or REST API
- **RESTful API**: Clean HTTP API with comprehensive OpenAPI/Swagger documentation
- **MCP Server**: Model Context Protocol server for AI assistant integrations
- **Streaming Responses**: Real-time Server-Sent Events (SSE) streaming of query processing results

### Infrastructure
- **Rust Library**: Integrate directly into your Rust applications
- **Integrated FalkorDB**: Built-in FalkorDB graph database with web browser interface
- **All-in-One Docker Solution**: Complete stack in a single container - database, web UI, API, and MCP server
- **Multi-Platform Support**: Docker images available for both AMD64 and ARM64 architectures

### AI & Quality
- **AI Model Integration**: Powered by genai for natural language processing with support for multiple providers
- **Dynamic Cypher Skills**: Load FalkorDB-specific best practices from external skill files with on-demand tool calling
- **Schema-Aware Generation**: Uses schema with example values for better query accuracy
- **Production Ready**: Comprehensive error handling, logging, and robust architecture
- **Environment Configuration**: Flexible configuration via `.env` file with fallback to request parameters

## Quick Start

### Using as a Rust Library

Add text-to-cypher to your `Cargo.toml`:

```toml
[dependencies]
# For library usage only (without REST server)
text-to-cypher = { version = "0.1", default-features = false }

# For full server capabilities
text-to-cypher = "0.1"
```

**Basic Example:**

```rust
use text_to_cypher::{TextToCypherClient, ChatRequest, ChatMessage, ChatRole};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a client
    let client = TextToCypherClient::new(
        "gpt-4o-mini",
        "your-api-key",
        "falkor://127.0.0.1:6379"
    );

    // Create a chat request
    let request = ChatRequest {
        messages: vec![
            ChatMessage {
                role: ChatRole::User,
                content: "Find all actors who appeared in movies released after 2020".to_string(),
            }
        ]
    };

    // Convert text to Cypher and execute
    let response = client.text_to_cypher("movies", request).await?;
    
    println!("Generated query: {}", response.cypher_query.unwrap());
    println!("Result: {}", response.cypher_result.unwrap());
    println!("Answer: {}", response.answer.unwrap());

    Ok(())
}
```

**More Examples:**

See the [library usage example](examples/library_usage.rs) for comprehensive examples including:
- Using the high-level `TextToCypherClient`
- Using core functions directly for more control
- Generating Cypher queries without execution

Run the example:
```bash
# Ensure FalkorDB is running
docker run -d -p 6379:6379 falkordb/falkordb:latest

# Set your API key
export OPENAI_API_KEY=your-key-here

# Run the example (library mode - no server dependencies)
cargo run --example library_usage --no-default-features
```

### Using from TypeScript/JavaScript

See [TypeScript Usage Guide](docs/TYPESCRIPT_USAGE.md) for detailed instructions on using text-to-cypher from TypeScript/JavaScript applications via REST API, Node.js native bindings, or WebAssembly.

### Using from Python

See [Python Usage Guide](docs/PYTHON_USAGE.md) for detailed instructions on using text-to-cypher from Python applications via REST API or PyO3 bindings.

### Using Docker (Recommended for Server)

The easiest way to get started is using our all-in-one Docker image that includes FalkorDB database, web browser interface, text-to-cypher API, and MCP server:

```bash
# Run the complete stack with all services
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  -e DEFAULT_MODEL=gpt-4o-mini -e DEFAULT_KEY=your-api-key \
  falkordb/text-to-cypher:latest

# Or using environment file
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  --env-file .env \
  falkordb/text-to-cypher:latest

# Or mounting .env file for full MCP server functionality
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  -v $(pwd)/.env:/app/.env:ro \
  falkordb/text-to-cypher:latest

# Custom ports using environment variables
docker run -p 6379:6379 -p 3000:3000 -p 9090:9090 -p 4001:4001 \
  -e REST_PORT=9090 -e MCP_PORT=4001 \
  -e DEFAULT_MODEL=gpt-4o-mini -e DEFAULT_KEY=your-api-key \
  falkordb/text-to-cypher:latest
```

### Available Services

Once running, access the services at:

- **FalkorDB Database**: `localhost:6379` (Redis protocol)
- **FalkorDB Web Interface**: `http://localhost:3000` (Interactive graph database browser)
- **Text-to-Cypher API**: `http://localhost:8080` (REST API)
- **Swagger UI**: `http://localhost:8080/swagger-ui/` (API documentation)
- **MCP Server**: `localhost:3001` (Model Context Protocol server)
- **OpenAPI Spec**: `http://localhost:8080/api-doc/openapi.json`

### Local Development

If you prefer to run locally without Docker:

```bash
# Prerequisites: You'll need FalkorDB running separately
docker run -d -p 6379:6379 falkordb/falkordb:latest

# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Clone and run the text-to-cypher service
git clone https://github.com/FalkorDB/text-to-cypher.git
cd text-to-cypher
cp .env.example .env  # Edit with your configuration
cargo run
```

The local development setup requires:

- **FalkorDB instance**: Running on port 6379 (can be Docker or native)
- **Rust environment**: For building and running the text-to-cypher service

## API Documentation

The API includes comprehensive Swagger UI documentation available at `/swagger-ui/` when running the server.

## Configuration

The application supports flexible configuration via environment variables or `.env` file:

### Core Settings

- `DEFAULT_MODEL`: Default AI model to use (e.g., "openai:gpt-4")
- `DEFAULT_KEY`: Default API key for the AI service

### Port Configuration

- `REST_PORT`: REST API server port (default: 8080)
- `MCP_PORT`: MCP server port for AI assistant integrations (default: 3001)
  - The MCP server provides an SSE endpoint at `/sse` on this port

### Optional Settings

- `FALKORDB_CONNECTION`: FalkorDB connection string (default: "falkor://127.0.0.1:6379")
- `SKILLS_DIR`: Path to a directory containing FalkorDB Cypher skill files (optional, see [Dynamic Cypher Skills]#dynamic-cypher-skills)

Create a `.env` file from the provided example:

```bash
cp .env.example .env
# Edit .env with your preferred default model and API key
```

### MCP Server Configuration

**Important**: The MCP server will only start if:

1. Both `DEFAULT_MODEL` and `DEFAULT_KEY` are configured
2. The `.env` file physically exists (not just environment variables)

For Docker deployments:

- Use `--env-file .env` or `-e` flags for HTTP server only (MCP server also starts if both MODEL and KEY are provided)
- Use `-v $(pwd)/.env:/app/.env:ro` to ensure MCP server starts with mounted `.env` file

## Architecture

The integrated Docker solution runs four concurrent services:

### FalkorDB Database (Port 6379)

- Graph database server with Redis protocol compatibility
- Stores and manages graph data structures
- Accessible via Redis clients and graph query languages

### FalkorDB Web Interface (Port 3000)

- Interactive web-based graph database browser
- Visual query builder and result visualization
- Database administration and monitoring tools
- Graph data exploration interface

### Text-to-Cypher HTTP API (Port 8080)

- Main REST API for text-to-cypher conversion
- Swagger UI documentation at `http://localhost:8080/swagger-ui/`
- OpenAPI specification at `http://localhost:8080/api-doc/openapi.json`
- Supports both streaming (SSE) and non-streaming responses

### MCP Server (Port 3001) - Conditional

- Model Context Protocol server for AI assistant integrations
- Provides `text_to_cypher` tool for natural language to Cypher conversion
- **Note**: MCP server only starts if both `DEFAULT_MODEL` and `DEFAULT_KEY` are configured

## Deployment Options

### Docker Deployment (Production)

The project provides an all-in-one Docker image that includes FalkorDB database, web browser interface, text-to-cypher API, and MCP server:

```bash
# Pull the latest image
docker pull docker.io/falkordb/text-to-cypher:latest

# Option 1: Complete stack with all services (recommended)
docker run -d \
  --name text-to-cypher-stack \
  -p 6379:6379 \
  -p 3000:3000 \
  -p 8080:8080 \
  -p 3001:3001 \
  -e DEFAULT_MODEL=gpt-4o-mini \
  -e DEFAULT_KEY=your-api-key \
  --restart unless-stopped \
  docker.io/falkordb/text-to-cypher:latest

# Option 2: Using environment file
docker run -d \
  --name text-to-cypher-stack \
  -p 6379:6379 \
  -p 3000:3000 \
  -p 8080:8080 \
  -p 3001:3001 \
  --env-file .env \
  --restart unless-stopped \
  docker.io/falkordb/text-to-cypher:latest

# Option 3: Mount .env file for full MCP functionality
docker run -d \
  --name text-to-cypher-stack \
  -p 6379:6379 \
  -p 3000:3000 \
  -p 8080:8080 \
  -p 3001:3001 \
  -v $(pwd)/.env:/app/.env:ro \
  --restart unless-stopped \
  docker.io/falkordb/text-to-cypher:latest

# View logs from all services
docker logs -f text-to-cypher-stack
```

### Docker Configuration Options

| Method | All Services | Use Case |
|--------|-------------|----------|
| `-e DEFAULT_MODEL=... -e DEFAULT_KEY=...` || Environment-based config |
| `--env-file .env` || File-based configuration |
| `-v $(pwd)/.env:/app/.env:ro` || Mounted configuration file |

**Note**: All four services (FalkorDB database, web interface, text-to-cypher API, and MCP server) will start when both `DEFAULT_MODEL` and `DEFAULT_KEY` are configured, regardless of how the environment variables are provided.

### Service Ports

| Service | Port | Description |
|---------|------|-------------|
| FalkorDB Database | 6379 | Redis protocol access to graph database |
| FalkorDB Web Interface | 3000 | Interactive web browser for graph exploration |
| Text-to-Cypher HTTP API | 8080 | REST API with Swagger documentation |
| MCP Server | 3001 | Model Context Protocol server for AI integrations |

### Docker Features

- **All-in-One Solution**: Complete graph database stack in a single container
- **Built-in Cypher Skills**: FalkorDB-specific Cypher best practices baked in from [FalkorDB/skills]https://github.com/FalkorDB/skills
- **Multi-Platform**: Support for both AMD64 and ARM64 architectures
- **Minimal Size**: Optimized Alpine Linux base for efficient deployment
- **Production Ready**: Includes supervisord for process management and logging
- **Security**: Services run with appropriate user permissions

### Environment Variables

Configure the application using environment variables or `.env` file:

- `DEFAULT_MODEL`: Default AI model (e.g., "gpt-4o-mini", "anthropic:claude-3")
- `DEFAULT_KEY`: Default API key for the AI service
- `FALKORDB_CONNECTION`: FalkorDB connection URL (default: "falkor://127.0.0.1:6379")
- `SKILLS_DIR`: Path to Cypher skills directory (default: `/app/skills` in Docker, see [Dynamic Cypher Skills]#dynamic-cypher-skills)

## MCP Server Usage

The MCP server provides a standardized interface for AI assistants to convert natural language questions into Cypher queries. This enables seamless integration with AI tools that support the Model Context Protocol.

### Using MCP Inspector

To test and interact with the MCP server, you can use the MCP Inspector:

1. **Start the text-to-cypher stack**:

```bash
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  -e DEFAULT_MODEL=gpt-4o-mini -e DEFAULT_KEY=your-api-key \
  docker.io/falkordb/text-to-cypher:latest
```

2. **Install MCP Inspector** (if not already installed):

```bash
npx -y @modelcontextprotocol/inspector
```

3. **Connect MCP Inspector to the server**:
   - Open MCP Inspector in your browser (typically `http://localhost:6274`)
   - Add a new server connection with these settings:
     - **Transport**: `stdio`
     - **Command**: `nc`
     - **Arguments**: `["localhost", "3001"]`

   Or if using a direct connection:
   - **Transport**: `sse`
   - **URL**: `http://localhost:3001/sse`

4. **Available Tools**:
   The MCP server exposes the following tool:

   #### `text_to_cypher`

   Converts natural language questions into Cypher queries for graph databases.

   **Parameters**:
   - `graph_name` (required): Name of the graph database to query
   - `question` (required): Natural language question to convert to Cypher

   **Example Usage in MCP Inspector**:

   ```json
   {
     "graph_name": "movies",
     "question": "Find all actors who appeared in movies released after 2020"
   }
   ```

5. **Example Workflow**:
   - Select the `text_to_cypher` tool in MCP Inspector
   - Fill in the parameters:
     - Graph name: `"social_network"`
     - Question: `"Who are the friends of John with more than 5 mutual connections?"`
   - Execute the tool
   - View the generated Cypher query and execution results

**Pro Tip**: You can also interact with the FalkorDB directly through the web interface at `http://localhost:3000` to create and explore graphs visually!

### Integration with AI Assistants

The MCP server enables AI assistants to:

- Convert natural language to Cypher queries
- Execute queries against FalkorDB graphs
- Provide structured responses with query results
- Handle complex graph database interactions seamlessly

### MCP Server Benefits

- **Standardized Interface**: Uses the Model Context Protocol for consistent AI tool integration
- **Streaming Support**: Real-time processing and response streaming
- **Error Handling**: Comprehensive error messages and validation
- **Documentation**: Auto-generated tool documentation with parameter descriptions and examples

## Getting Started

### Prerequisites

- **For Docker (Recommended)**: Docker installed on your system
- **For Local Development**:
  - Rust (latest stable version)
  - FalkorDB instance (can be run via Docker: `docker run -d -p 6379:6379 falkordb/falkordb:latest`)

### Running the Complete Stack

#### Using Docker (Recommended)

```bash
# Run the complete integrated stack
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  -e DEFAULT_MODEL=gpt-4o-mini -e DEFAULT_KEY=your-api-key \
  docker.io/falkordb/text-to-cypher:latest
```

#### Local Development

```bash
# Start FalkorDB separately
docker run -d -p 6379:6379 falkordb/falkordb:latest

# Run text-to-cypher service
cargo run
```

### Access the Services

Once running, access the services at:

- **FalkorDB Web Interface**: `http://localhost:3000` (Interactive graph browser)
- **Text-to-Cypher API**: `http://localhost:8080`
- **Swagger UI**: `http://localhost:8080/swagger-ui/`
- **OpenAPI spec**: `http://localhost:8080/api-doc/openapi.json`
- **FalkorDB Database**: `localhost:6379` (Redis protocol)
- **MCP Server**: `localhost:3001` (Model Context Protocol)

### Building for Production

#### Docker Build (Local)

```bash
# Build locally using the build script
./docker-build.sh

# Or build manually (defaults to SKILLS_REF=main for local/dev builds)
docker build -t text-to-cypher:latest .

# For reproducible production builds, pass a pinned FalkorDB/skills ref
docker build --build-arg SKILLS_REF=<falkordb-skills-commit-sha> -t text-to-cypher:latest .
```

#### Using Pre-built Images

```bash
# Pull from Docker Hub
docker pull docker.io/falkordb/text-to-cypher:latest

# Available tags: latest, v1.0.0, v0.1.0-beta.x, etc.
```

#### Native Build

```bash
cargo build --release
```

## Testing

The library includes comprehensive unit tests with 33+ test cases covering:

- **Library API tests** ([src/lib.rs]src/lib.rs#L409): `TextToCypherClient` construction, request/response serialization, chat types
- **Processor tests** ([src/processor.rs]src/processor.rs#L273): Request/response handling, status checks, serialization
- **Validator tests** ([src/validator.rs]src/validator.rs): Cypher query validation and security checks
- **Formatter tests** ([src/formatter.rs]src/formatter.rs): Result formatting for various data types
- **Schema tests** ([src/schema/discovery.rs]src/schema/discovery.rs): Schema discovery and validation

Run all tests:
```bash
# Run library tests only
cargo test --lib

# Run all tests including integration tests
cargo test

# Run with output
cargo test -- --nocapture
```

## Development

### Prerequisites

- [Rust]https://www.rust-lang.org/tools/install (stable)
- [just]https://github.com/casey/just#installation (recommended task runner)

### Quick Start with `just`

```bash
# List all available recipes
just

# Download FalkorDB Cypher skills + run lint + tests
just check

# Start development server (auto-downloads skills if missing)
just dev

# Download skills manually
just download-skills

# Download skills pinned to a specific version
just download-skills-pinned v1.0.0

# List loaded skills
just list-skills
```

### Available Recipes

| Recipe | Description |
|--------|-------------|
| `just download-skills` | Download latest FalkorDB Cypher skills |
| `just download-skills-pinned <ref>` | Download skills at a specific branch/tag/commit |
| `just build` | Build in debug mode |
| `just build-release` | Build in release mode |
| `just build-lib` | Build library only (no server deps) |
| `just fmt` | Check formatting |
| `just clippy` | Run clippy with CI-level strictness |
| `just lint` | Run all lints (fmt + clippy) |
| `just test` | Run all tests |
| `just check` | Full CI check (lint + test) |
| `just dev` | Start development server with skills |
| `just run` | Start release server with skills |
| `just docker-build [version] [skills_ref]` | Build Docker image locally (defaults to latest skills from `main`) |
| `just docker-push <version> <registry> <skills_ref>` | Build and push Docker image with a pinned skills ref |
| `just list-skills` | Show all loaded skills |
| `just clean` | Clean build artifacts and skills |

### Code Quality

The project maintains high code quality standards:

```bash
# Using just (recommended)
just lint    # fmt + clippy
just test    # run all tests
just check   # lint + test

# Or with cargo directly
cargo fmt
cargo clippy -- -W clippy::pedantic -W clippy::nursery -D warnings
cargo test
```

### Project Structure

```text
text-to-cypher/
├── src/
│   ├── main.rs              # Main application and HTTP server
│   ├── chat.rs              # Chat message types and handling
│   ├── error.rs             # Error types and handling
│   ├── formatter.rs         # Query result formatting
│   ├── mcp/                 # Model Context Protocol server
│   ├── schema/              # Graph schema discovery
│   ├── skills/              # Dynamic Cypher skill loading
│   │   ├── mod.rs           # Skill catalog, tool calling, provider gating
│   │   ├── parser.rs        # YAML frontmatter + markdown parser
│   │   └── loader.rs        # Directory-based skill loader
│   └── template.rs          # Template engine for prompts
├── templates/               # AI prompt templates
│   ├── system_prompt.txt    # System prompt for AI
│   ├── user_prompt.txt      # User query template
│   └── last_request_prompt.txt # Final response template
├── skills/                  # Downloaded Cypher skills (gitignored)
├── justfile                 # Development task recipes
├── Dockerfile               # All-in-one Docker image with FalkorDB + skills
├── supervisord.conf         # Process management configuration
├── entrypoint.sh            # Docker container startup script
├── .dockerignore            # Docker build context filtering
└── docker-build.sh          # Convenient Docker build script
```

## API Usage Examples

### Basic Text-to-Cypher Request

```bash
curl -X POST "http://localhost:8080/text_to_cypher" \
  -H "Content-Type: application/json" \
  -d '{
    "graph_name": "movies",
    "chat_request": {
      "messages": [
        {
          "role": "User",
          "content": "Find all actors who appeared in movies released after 2020"
        }
      ]
    },
    "model": "gpt-4o-mini",
    "key": "your-api-key"
  }'
```

### Using the FalkorDB Web Interface

1. **Access the web interface**: Open `http://localhost:3000` in your browser
2. **Connect to database**: The interface automatically connects to the local FalkorDB instance
3. **Create sample data**: Use the visual interface to create nodes and relationships
4. **Run queries**: Test Cypher queries directly in the web interface
5. **Export/Import**: Save your graph data or load sample datasets

### Using Server-Sent Events (SSE)

The API supports streaming responses for real-time progress updates:

```javascript
const eventSource = new EventSource('/text_to_cypher', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    graph_name: "social_network",
    chat_request: {
      messages: [{ role: "User", content: "Who are John's friends?" }]
    }
  })
});

eventSource.onmessage = (event) => {
  const progress = JSON.parse(event.data);
  console.log('Progress:', progress);
};
```

### Complete Workflow Example

```bash
# 1. Start the complete stack
docker run -p 6379:6379 -p 3000:3000 -p 8080:8080 -p 3001:3001 \
  -e DEFAULT_MODEL=gpt-4o-mini -e DEFAULT_KEY=your-api-key \
  docker.io/falkordb/text-to-cypher:latest

# 2. Create a graph using FalkorDB web interface (http://localhost:3000)
# Add some sample data: people, relationships, etc.

# 3. Query using natural language via the API
curl -X POST "http://localhost:8080/text_to_cypher" \
  -H "Content-Type: application/json" \
  -d '{
    "graph_name": "social_network",
    "chat_request": {
      "messages": [
        {
          "role": "User", 
          "content": "Find all people who have more than 3 friends"
        }
      ]
    },
    "model": "gpt-4o-mini",
    "key": "your-api-key"
  }'

# 4. Use MCP server for AI assistant integrations (port 3001)
# Connect your AI assistant to http://localhost:3001
```

## Publishing to crates.io

This library is designed to be published to [crates.io](https://crates.io/crates/text-to-cypher), making it easy to use in any Rust project.

### For Maintainers

To publish a new version to [crates.io](https://crates.io/crates/text-to-cypher):

1. **Ensure you have a crates.io account and are logged in**:
   ```bash
   # First time only: Create account at https://crates.io/ and get API token
   cargo login
   ```

2. **Update the version** in `Cargo.toml` following [Semantic Versioning]https://semver.org/:
   ```toml
   [package]
   version = "0.1.1"  # Increment as needed
   ```

3. **Update CHANGELOG** (if exists) with version changes and release notes.

4. **Ensure all tests pass** (including doc tests):
   ```bash
   cargo test
   cargo test --doc
   ```

5. **Run code quality checks**:
   ```bash
   # Format code
   cargo fmt
   
   # Run clippy with pedantic lints
   cargo clippy --lib -- -W clippy::pedantic -W clippy::nursery -D warnings
   ```

6. **Build and test both library and server modes**:
   ```bash
   # Test library-only mode (minimal dependencies)
   cargo build --lib --no-default-features
   
   # Test with server features (default)
   cargo build
   
   # Test the example
   cargo run --example library_usage --no-default-features
   ```

7. **Do a dry-run publish** to verify package contents:
   ```bash
   cargo publish --dry-run
   ```
   
   Review the output to ensure:
   - All necessary files are included
   - No sensitive files are accidentally included
   - Package size is reasonable

8. **Create a git tag** for the version:
   ```bash
   git tag -a v0.1.1 -m "Release version 0.1.1"
   git push origin v0.1.1
   ```

9. **Publish to crates.io**:
   ```bash
   cargo publish
   ```
   
   Note: Publishing is **permanent** - you cannot delete or replace a published version.

10. **Verify the published crate**:
    ```bash
    # Check on crates.io
    open https://crates.io/crates/text-to-cypher
    
    # Test installing from crates.io
    cargo install text-to-cypher --version 0.1.1
    ```

### For Users

Once published, users can easily add text-to-cypher to their projects:

```toml
[dependencies]
# Library-only usage (no REST server)
text-to-cypher = { version = "0.1", default-features = false }

# With REST server capabilities
text-to-cypher = "0.1"
```

The library is published with:
- **default features**: Includes REST API server, Swagger UI, MCP server
- **no-default-features**: Core library only (schema discovery, query generation, execution)

## Troubleshooting

### Common Issues

**Services not starting**:

- Ensure all required ports (6379, 3000, 8080, 3001) are available
- Check that `DEFAULT_MODEL` and `DEFAULT_KEY` are properly configured
- View logs: `docker logs -f <container-name>`

**MCP Server not starting**:

- Verify both `DEFAULT_MODEL` and `DEFAULT_KEY` environment variables are set
- For local builds, ensure `.env` file exists in the working directory

**FalkorDB connection issues**:

- The integrated FalkorDB automatically starts with the container
- No external FalkorDB instance needed when using the Docker image
- Database is accessible at `localhost:6379` (Redis protocol)

**Web interface not accessible**:

- Ensure port 3000 is properly mapped: `-p 3000:3000`
- Try accessing `http://localhost:3000` directly
- Check firewall settings if running on a remote server

### Getting Help

- **API Documentation**: `http://localhost:8080/swagger-ui/`
- **Web Interface**: `http://localhost:3000` for graph exploration
- **Logs**: Use `docker logs -f <container-name>` to view all service logs
- **Issues**: Report problems at [GitHub Issues]https://github.com/FalkorDB/text-to-cypher/issues

## Dynamic Cypher Skills

Text-to-cypher supports loading FalkorDB-specific Cypher expertise from external skill files at runtime. This allows the LLM to generate better, more efficient Cypher queries by leveraging domain-specific knowledge about FalkorDB's query engine.

### How It Works

The system uses a **two-tier architecture** for skill loading:

```text
┌─────────────────────────────────────────────────────────────┐
│                     System Prompt                           │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Tier 1: Skill Catalog (compact)                      │  │
│  │  - apply-cypher-limitations: Avoid FalkorDB pitfalls  │  │
│  │  - use-parameters: Use parameterized queries          │  │
│  │  - fulltext-search: Full-text search syntax           │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                    LLM decides it needs
                    more detail on a skill
┌─────────────────────────────────────────────────────────────┐
│  Tier 2: Tool Call → read_skill("apply-cypher-limitations") │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Full skill content returned:                         │  │
│  │  # Apply Cypher Limitations                           │  │
│  │  - <> and != are NOT index-accelerated               │  │
│  │  - Use positive predicates when possible              │  │
│  │  - Self-referencing relationships are directed...     │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
```

**Tier 1 (Catalog)**: A compact list of skill names and descriptions is injected into the system prompt. This gives the LLM awareness of available expertise without bloating the context window.

**Tier 2 (Tool Calling)**: When the LLM determines it needs detailed guidance for a particular query, it calls the `read_skill` tool to load the full skill content on-demand. This keeps prompts lean for simple queries while enabling deep expertise for complex ones.

### Provider Support

Tool calling (Tier 2) is supported by these providers:

| Provider | Tool Calling | Behavior |
|----------|:----------:|----------|
| OpenAI || On-demand skill loading via `read_skill` tool |
| Anthropic || On-demand skill loading via `read_skill` tool |
| Gemini || On-demand skill loading via `read_skill` tool |
| xAI || On-demand skill loading via `read_skill` tool |
| DeepSeek || On-demand skill loading via `read_skill` tool |
| Groq || All skill content injected directly into prompt |
| Ollama || All skill content injected directly into prompt |
| Cohere || All skill content injected directly into prompt |

For providers without tool support, the system automatically falls back to injecting all skill content directly into the system prompt. Every provider benefits from skills — only the delivery mechanism differs.

### Advantages & Limitations

**Advantages:**
- 🎯 **Smaller prompts** — Only skill names/descriptions in the base prompt; full content loaded on-demand
- 🔧 **Maintainable** — Skills live in plain markdown files, easy to add/edit/remove without code changes
- 🔌 **Pluggable** — Load different skill sets for different deployments or use cases
- 🚀 **Better queries** — LLM generates FalkorDB-optimized Cypher by leveraging domain-specific knowledge
- ⬇️ **Backward compatible** — Without `SKILLS_DIR`, behavior is identical to the base system
- 🔄 **Universal fallback** — Providers without tool support still get all skill content (just via prompt injection)

**Limitations:**
- 📡 **Extra LLM round-trips** — Tool calling adds 1-3 additional API calls when skills are requested
- 💰 **Increased token usage** — Skill content adds tokens to the context (either via tools or prompt injection)
- 📁 **Requires skill files** — You need to provide/maintain the skill directory (see [FalkorDB/skills]https://github.com/FalkorDB/skills/tree/main/cypher-skills for ready-made skills)
- 🤖 **Provider-dependent** — Tool calling quality varies by provider; some models may over-request or under-request skills

### Setting Up Skills

#### Docker (zero setup required)

The Docker image comes with FalkorDB Cypher skills **pre-installed** at `/app/skills`. Skills are enabled by default — no configuration needed:

```bash
# Skills are already baked in — just run!
docker run -d \
  -e DEFAULT_MODEL=gpt-4o-mini \
  -e DEFAULT_KEY=your-api-key \
  -p 8080:8080 \
  docker.io/falkordb/text-to-cypher:latest
```

To override with custom skills, mount your own directory:

```bash
docker run -d \
  -e DEFAULT_MODEL=gpt-4o-mini \
  -e DEFAULT_KEY=your-api-key \
  -e SKILLS_DIR=/app/custom-skills \
  -v /path/to/your/skills:/app/custom-skills:ro \
  -p 8080:8080 \
  docker.io/falkordb/text-to-cypher:latest
```

Release Docker builds require a full `FalkorDB/skills` commit SHA. Use `./docker-build.sh --skills-ref <commit-sha>` or rebuild manually with `--build-arg SKILLS_REF=<commit-sha>`; reserve `SKILLS_REF=main` for local/dev builds only.

#### Development (using `just`)

The easiest way to set up skills locally:

```bash
# Install just: https://github.com/casey/just#installation

# Download latest FalkorDB Cypher skills
just download-skills

# Or pin to a specific version
just download-skills-pinned v1.0.0

# Start dev server (auto-downloads skills if missing)
just dev

# List available skills
just list-skills
```

#### Manual setup

```bash
# Download skills via curl
mkdir -p /tmp/skills-extract
curl -sL https://github.com/FalkorDB/skills/archive/main.tar.gz \
  | tar -xz -C /tmp/skills-extract --strip-components=1
mv /tmp/skills-extract/cypher-skills ./skills
rm -rf /tmp/skills-extract

# Point the server at them
export SKILLS_DIR=./skills
cargo run
```

#### Skill file format

Each skill lives in its own directory with a `skill.md` file containing YAML frontmatter and markdown body:

```text
skills/
  apply-cypher-limitations/
    skill.md
  use-parameters/
    skill.md
  fulltext-search/
    skill.md
```

A `skill.md` file looks like:

```markdown
---
name: Apply Cypher Limitations
description: Avoid FalkorDB-specific Cypher pitfalls and write optimized queries
---

# Apply Cypher Limitations

## Usage
- The `<>` and `!=` operators are NOT index-accelerated in FalkorDB
- Prefer positive predicates when they preserve the user's intent
- Use `<>` / `!=` only when exclusion is explicitly required

## Example
Instead of: `MATCH (n:Person) WHERE n.age <> 30 RETURN n`
Prefer: `MATCH (n:Person) WHERE n.age > 30 OR n.age < 30 RETURN n`
```

### Library Usage with Skills

**Basic — load skills from a directory:**

```rust
use text_to_cypher::{TextToCypherClient, SkillCatalog, ChatRequest, ChatMessage, ChatRole};
use std::path::Path;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load skills from a directory
    let catalog = SkillCatalog::from_directory(Path::new("./cypher-skills"))?;
    println!("Loaded {} skills", catalog.len());

    // Create a client with skills
    let client = TextToCypherClient::new(
        "gpt-4o-mini",
        "your-api-key",
        "falkor://127.0.0.1:6379"
    ).with_skills(catalog);

    // Use as normal — skills are automatically used during query generation
    let request = ChatRequest {
        messages: vec![
            ChatMessage {
                role: ChatRole::User,
                content: "Find people older than 30 who are NOT named John".to_string(),
            }
        ]
    };

    let response = client.text_to_cypher("social", request).await?;
    // The LLM may use the "apply-cypher-limitations" skill to avoid
    // using <> operator and generate an optimized query instead
    println!("Query: {}", response.cypher_query.unwrap());

    Ok(())
}
```

**Advanced — use the lower-level API with skills:**

```rust
use text_to_cypher::{core, SkillCatalog, ChatRequest, ChatMessage, ChatRole};
use std::path::Path;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let catalog = SkillCatalog::from_directory(Path::new("./cypher-skills"))?;
    let client = core::create_genai_client(Some("your-api-key"));

    let schema = core::discover_graph_schema(
        "falkor://127.0.0.1:6379",
        "movies"
    ).await?;

    let chat_req = ChatRequest {
        messages: vec![
            ChatMessage {
                role: ChatRole::User,
                content: "Find actors who acted in sci-fi movies".to_string(),
            }
        ]
    };

    // Generate query with skills — tool calling happens automatically
    let query = core::generate_cypher_query_with_skills(
        &chat_req,
        &schema,
        &client,
        "gpt-4o-mini",
        Some(&catalog),
    ).await?;

    println!("Generated: {}", query);
    Ok(())
}
```

**Without skills — everything works exactly as before:**

```rust
// No skills, no changes needed
let client = TextToCypherClient::new("gpt-4o-mini", "key", "falkor://127.0.0.1:6379");
let response = client.text_to_cypher("graph", request).await?;
```

## Recent Improvements

This project implements best practices from current research and industry leaders:

### Query Quality & Reliability
- **Query Validation**: Automatic syntax and safety validation before execution
- **Self-Healing**: Failed queries are automatically regenerated with error feedback
- **Enhanced Schema**: Schema discovery now includes example values for better context

### Based on Research From
- [Neo4j Labs Text2Cypher]https://github.com/neo4j-labs/text2cypher - Industry best practices
- [arXiv 2412.10064]https://arxiv.org/abs/2412.10064 - Text2Cypher academic research
- [GraphRAG]https://graphrag.com/reference/graphrag/text2cypher/ - Microsoft's approach
- [MDPI Research]https://www.mdpi.com/2076-3417/15/15/8206 - Reinforcement learning techniques

### Documentation
- [Improvements Guide]docs/IMPROVEMENTS.md - Detailed technical improvements
- [Best Practices]docs/BEST_PRACTICES.md - Usage guidelines and optimization tips

## License

This project is licensed under the MIT License.