A doc store built with React. Organize markdown files in folders, full REST API, and an MCP server
10K+
A wiki and document store built with React and Express.
Single-user personal knowledge base - A full-stack TypeScript application that provides a beautiful, intuitive interface for creating and managing markdown documents organized in a hierarchical folder structure.
⚠️ Note: Codex is designed as a single-user application. It does not support concurrent multi-user editing or collaboration features. Perfect for personal wikis, note-taking, and documentation.
data/templates/).md files to navigate within the app; anchor links scroll to headingsWhen creating a new page, Codex can start from a template instead of a blank page.
data/templates/*.mdtemplate: Your Template Name (display name)autoname: true|false (auto-generate a filename when creating)Codex supports Mermaid diagrams in markdown via fenced code blocks:
```mermaid
graph TD
A --> B
```
Codex includes several security features to protect your data:
AUTH_PASSWORD (not recommended for public deployments)429 Too Many Requests when limit is exceededAll login attempts are logged with timestamps and IP addresses:
✓ Successful login from 192.168.1.100 - Successful authentication✗ Failed login attempt from 192.168.1.100 - Invalid passwordLogin attempt without password from 192.168.1.100 - Missing passwordLogin attempt when auth disabled from 192.168.1.100 - Auth not configuredHTTP request logging (via morgan):
Helmet middleware provides:
AUTH_PASSWORD for deploymentsSESSION_SECRET in productionNODE_ENV=production)Codex is designed to be accessible to all users, including those using assistive technologies:
<header>, <nav>, <main>, <section>, <aside>, and <article> elementsaria-live) announce dynamic content updatesrole="tree", role="button", role="dialog") for enhanced navigationtabIndex attributesj/k) in folder tree, page list, and search resultsThe accessibility features ensure Codex can be used effectively by people with:
# Clone the repository
git clone https://github.com/bocan/codex.git
cd codex
# Install dependencies
make install
Create a .env file in the root directory:
# Required: Set your password
AUTH_PASSWORD=your-secure-password-here
# Optional: Server port (default: 3001)
PORT=3001
# Start both server and client
make dev
# Visit http://localhost:3000
# Login with your AUTH_PASSWORD
The fastest way to get started using the Makefile:
# Install all dependencies
make install
# Run the application
make dev
Then open http://localhost:3000 in your browser!
make install
npm run install:all
# Install root dependencies
npm install
# Install server dependencies
cd server && npm install
# Install client dependencies
cd ../client && npm install
# Run both server and client in development mode
make dev
# Or run them separately
make dev-server # Runs server on port 3001
make dev-client # Runs client on port 3000
# Run both concurrently
npm run dev
# Or run separately
npm run dev:server
npm run dev:client
The application will be available at:
# Using Make
make build
# Using npm
npm run build
This creates optimized production builds in:
server/dist/ - Compiled backendclient/dist/ - Optimized frontend bundleCodex can be run in Docker for simplified deployment. In production mode, Express serves both the API and the React UI from a single port (3001).
Official multi-architecture (AMD64/ARM64) images are available on Docker Hub:
docker pull bocan/codex:latest
Available tags:
latest - Latest stable release2.7.0 - Specific version (example)2.7 - Minor version (example)2 - Major version (example)Image verification (signed with Cosign):
cosign verify bocan/codex:latest \
--certificate-identity-regexp=https://github.com/bocan/codex \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
Supply chain security:
To inspect the SBOM:
docker buildx imagetools inspect bocan/codex:latest --format "{{ json .SBOM }}"
# Build and start the container
docker compose up -d --build
# View logs
docker compose logs -f codex
# Stop the container
docker compose down
The application will be available at http://localhost:3001 (both UI and API on the same port).
# Build the image
docker build -t codex .
# Run the container
docker run -d \
--name codex \
-p 3001:3001 \
-v $(pwd)/data:/app/data \
-e NODE_ENV=production \
codex
# View logs
docker logs -f codex
# Stop and remove
docker stop codex && docker rm codex
Environment Variables (in docker-compose.yml):
NODE_ENV=production - Runs in production modePORT=3001 - Server port (default)AUTH_PASSWORD=your-password - Set to enable authentication (optional)TRUST_PROXY=true - Enable when behind a reverse proxy with HTTPSVolume Mounting:
./data:/app/data - Persists your wiki data outside the containerImportant: Due to secure cookie requirements, there are two ways to run Codex with authentication:
Remove or comment out the AUTH_PASSWORD environment variable in docker-compose.yml:
environment:
- NODE_ENV=production
- PORT=3001
# - AUTH_PASSWORD=your-password # Commented out
This allows direct HTTP access without authentication, suitable for local testing.
For production with authentication, deploy behind a reverse proxy (nginx, Caddy, Traefik) that:
X-Forwarded-Proto: https headerTRUST_PROXY=true in the environment variablesExample with nginx:
server {
listen 443 ssl;
server_name wiki.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Why? In production mode, session cookies use secure: auto, which requires HTTPS. Direct HTTP access with a password set will fail because the browser won't send the secure cookie. The reverse proxy provides HTTPS termination while communicating with Codex via HTTP internally.
Codex includes a Model Context Protocol (MCP) server that allows AI agents like Claude, GitHub Copilot, and other MCP-compatible clients to interact with your documentation.
Enable the MCP server by setting environment variables:
export MCP_ENABLED=true
export MCP_API_KEY=your-secure-api-key
Start the server (runs alongside the main app):
npm run dev:mcp -w server # Development with hot reload
Connect your MCP client to http://localhost:3002/mcp
The MCP server exposes 12 tools for AI agents:
| Tool | Description |
|---|---|
search_pages | Search documentation by query |
get_page | Read a page's content |
create_page | Create a new page |
update_page | Update an existing page |
delete_page | Delete a page |
rename_page | Rename a page |
move_page | Move a page to another folder |
list_folders | Get folder hierarchy |
list_pages | List pages in a folder |
create_folder | Create a new folder |
delete_folder | Delete an empty folder |
rename_folder | Rename a folder |
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"codex": {
"url": "http://localhost:3002/mcp",
"headers": { "Authorization": "Bearer your-api-key" }
}
}
}
VS Code / GitHub Copilot (settings or mcp.json):
{
"servers": {
"codex": {
"type": "http",
"url": "http://localhost:3002/mcp",
"headers": { "Authorization": "Bearer your-api-key" }
}
}
}
For full documentation, see server/src/mcp/README.md.
The REST API is available at http://localhost:3001/api
GET /api/health
Response:
{
"status": "ok"
}
GET /api/folders
Response:
{
"name": "root",
"path": "/",
"type": "folder",
"children": [
{
"name": "Projects",
"path": "Projects",
"type": "folder",
"children": []
}
]
}
POST /api/folders
Content-Type: application/json
{
"path": "folder-name"
}
# or nested: "parent/subfolder"
Example:
curl -X POST http://localhost:3001/api/folders \
-H "Content-Type: application/json" \
-d '{"path": "My Notes"}'
DELETE /api/folders/:path
Example:
curl -X DELETE http://localhost:3001/api/folders/My%20Notes
PUT /api/folders/rename
Content-Type: application/json
{
"oldPath": "old-name",
"newPath": "new-name"
}
Example:
curl -X PUT http://localhost:3001/api/folders/rename \
-H "Content-Type: application/json" \
-d '{"oldPath": "My Notes", "newPath": "Work Notes"}'
GET /api/pages?folder=folder-path
Response:
[
{
"name": "page1.md",
"path": "folder/page1.md",
"type": "file"
}
]
GET /api/pages/:path
Response:
{
"path": "folder/page1.md",
"content": "# Page Title\n\nContent here..."
}
Example:
curl http://localhost:3001/api/pages/My%20Notes/hello.md
POST /api/pages
Content-Type: application/json
{
"path": "folder/page.md",
"content": "# Page Title\n\nContent here..."
}
Example:
curl -X POST http://localhost:3001/api/pages \
-H "Content-Type: application/json" \
-d '{"path": "My Notes/hello.md", "content": "# Hello World\n\nThis is my first page!"}'
PUT /api/pages/:path
Content-Type: application/json
{
"content": "# Updated Content"
}
Example:
curl -X PUT http://localhost:3001/api/pages/My%20Notes/hello.md \
-H "Content-Type: application/json" \
-d '{"content": "# Updated Hello\n\nNew content!"}'
DELETE /api/pages/:path
Example:
curl -X DELETE http://localhost:3001/api/pages/My%20Notes/hello.md
PUT /api/pages/rename/file
Content-Type: application/json
{
"oldPath": "old-page.md",
"newPath": "new-page.md"
}
Example:
curl -X PUT http://localhost:3001/api/pages/rename/file \
-H "Content-Type: application/json" \
-d '{"oldPath": "My Notes/hello.md", "newPath": "My Notes/welcome.md"}'
PUT /api/pages/move
Content-Type: application/json
{
"oldPath": "folder1/page.md",
"newFolderPath": "folder2"
}
# Returns: { "success": true, "newPath": "folder2/page.md" }
Example:
curl -X PUT http://localhost:3001/api/pages/move \
-H "Content-Type: application/json" \
-d '{"oldPath": "My Notes/hello.md", "newFolderPath": "Projects"}'
make clean && make installMIT
Made with ❤️ for taking better notes
Content type
Image
Digest
sha256:96fd91df1…
Size
210.1 MB
Last updated
12 days ago
docker pull bocan/codex