curlpipe/ox
The simple but flexible text editor
Single-maintainer risk — review before adopting
weakest axiscopyleft license (GPL-2.0) — review compatibility; top contributor handles 99% of recent commits
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2w ago
- ✓2 active contributors
- ✓GPL-2.0 licensed
Show all 8 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Small team — 2 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 99% of recent commits
- ⚠GPL-2.0 is copyleft — check downstream compatibility
What would change the summary?
- →Use as dependency Concerns → Mixed if: relicense under MIT/Apache-2.0 (rare for established libs)
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/curlpipe/ox)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/curlpipe/ox on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: curlpipe/ox
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/curlpipe/ox shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Single-maintainer risk — review before adopting
- Last commit 2w ago
- 2 active contributors
- GPL-2.0 licensed
- CI configured
- Tests present
- ⚠ Small team — 2 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 99% of recent commits
- ⚠ GPL-2.0 is copyleft — check downstream compatibility
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live curlpipe/ox
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/curlpipe/ox.
What it runs against: a local clone of curlpipe/ox — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in curlpipe/ox | Confirms the artifact applies here, not a fork |
| 2 | License is still GPL-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 45 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of curlpipe/ox. If you don't
# have one yet, run these first:
#
# git clone https://github.com/curlpipe/ox.git
# cd ox
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of curlpipe/ox and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "curlpipe/ox(\\.git)?\\b" \\
&& ok "origin remote is curlpipe/ox" \\
|| miss "origin remote is not curlpipe/ox (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(GPL-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"GPL-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is GPL-2.0" \\
|| miss "license drift — was GPL-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/editor/mod.rs" \\
&& ok "src/editor/mod.rs" \\
|| miss "missing critical file: src/editor/mod.rs"
test -f "kaolinite/src/document/mod.rs" \\
&& ok "kaolinite/src/document/mod.rs" \\
|| miss "missing critical file: kaolinite/src/document/mod.rs"
test -f "src/config/mod.rs" \\
&& ok "src/config/mod.rs" \\
|| miss "missing critical file: src/config/mod.rs"
test -f "src/events.rs" \\
&& ok "src/events.rs" \\
|| miss "missing critical file: src/events.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 45 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~15d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/curlpipe/ox"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Ox is a lightweight, terminal-based text editor written in Rust that prioritizes configurability through Lua scripting and a plugin system. It provides syntax highlighting, multi-cursor editing, macros, splits, and a file tree—all without being based on existing editors like Vim or Nano. The core text manipulation engine lives in kaolinite/, a separate workspace crate handling documents, cursors, searching, and line operations. Monorepo with two crates: main ox/ (TUI/config/plugins) depends on kaolinite/ (core document model). kaolinite/src/document/ contains modular submodules: cursor.rs, lines.rs, editing.rs, disk.rs, words.rs. Plugins live in plugins/ as Lua files; example config in config/.oxrc (Lua). Event handling and searching live alongside the document model.
👥Who it's for
Terminal-native developers and power users who want a configurable TUI editor without the steep learning curve of Vim/Emacs, but with extensibility through Lua plugins (Git integration, Discord RPC, Emmet, AI tools). Contributors are those building text editor features or plugin ecosystems.
🌱Maturity & risk
Actively developed at v0.7.7 with CI/CD pipelines in .github/workflows/, a test suite in kaolinite/tests/, and example configs in config/. The project shows reasonable maturity with modular architecture, but the relatively modest star count and pre-1.0 versioning suggest it's a solid independent project rather than a widely-adopted mainstream editor.
Single crate in workspace (kaolinite/) with moderate dependency count (crossterm, mlua, synoptic, regex, etc.); mlua vendored Lua adds size. No obvious signs of abandonment, but visibility into open issues/PRs isn't in the file listing. Windows support is noted as secondary (platform-specific dependencies), so breaking changes there are possible. Lua plugin system introduces security surface if plugins can execute arbitrary code.
Active areas of work
Unable to infer from file listing alone (no git log, issue tracker, or PR data visible). However, the presence of .todo.md and kaolinite/.further.todo.md suggests active feature development. Recent work appears to include plugin infrastructure (multiple .lua plugins present) and platform support improvements.
🚀Get running
git clone https://github.com/curlpipe/ox.git
cd ox
cargo build --release
./target/release/ox # run the editor
Optionally source the example config: cp config/.oxrc ~/.oxrc (Lua config file).
Daily commands:
Development mode: cargo run (from workspace root). Release build: cargo build --release, then ./target/release/ox. The build.sh script is present—check it for specific build flags. Editor starts with default or custom config from ~/.oxrc.
🗺️Map of the codebase
src/main.rs— Entry point for the entire editor application; initializes the UI, event loop, and core editor state.src/editor/mod.rs— Core Editor struct and main business logic; orchestrates all editing operations, document management, and command dispatch.kaolinite/src/document/mod.rs— Document abstraction layer that manages text content, cursor position, and file I/O; foundational to all text operations.src/config/mod.rs— Configuration system that loads and parses the .oxrc Lua config file; controls all customizable behavior including keybindings.src/events.rs— Event handling system that routes user input (keyboard, mouse, terminal events) to the editor state machine.src/plugin/run.lua— Lua plugin execution runtime; bridges the Rust core to user-defined Lua scripts for extensibility.src/ui.rs— Terminal UI rendering layer; manages screen layout, color output, and all visual presentation to the user.
🧩Components & responsibilities
- Editor (src/editor/mod.rs) (Rust core logic) — Orchestrates all editing operations, maintains open document list, routes commands, tracks dirty state
- Failure mode: If Editor panics, entire session is lost; no recovery
- Document (kaolinite/src/document/mod.rs) (Rope or gap buffer for text, Vec) — Owns text buffer, cursor, undo history, and file metadata; enforces invariants on text and position
🛠️How to make changes
Add a new editor command
- Define the command in src/editor/mod.rs in the handle_command() method or as a new match arm (
src/editor/mod.rs) - Add keyboard binding in config/.oxrc or allow users to bind it via keybindings config (
config/.oxrc) - Implement the action logic in appropriate editor submodule (src/editor/editing.rs for text ops, src/editor/cursor.rs for movement, etc.) (
src/editor/editing.rs)
Add a new Lua plugin
- Create new .lua file in plugins/ directory (e.g., plugins/my_feature.lua) (
plugins/my_feature.lua) - Use Lua APIs exposed in src/plugin/bootstrap.lua to interact with the editor (e.g., register_command, subscribe_to_event) (
src/plugin/bootstrap.lua) - Register plugin in user's .oxrc config or load via plugin manager in src/plugin/plugin_manager.lua (
src/plugin/plugin_manager.lua)
Add a new syntax highlighting rule
- Define file type detection in src/editor/filetypes.rs to identify the language/filetype (
src/editor/filetypes.rs) - Create tokenization rules in src/editor/scanning.rs or delegate to plugin-based highlighting (
src/editor/scanning.rs) - Map token types to colors in src/config/highlighting.rs and color theme (plugins/themes/*.lua) (
src/config/highlighting.rs)
Add a new configuration option
- Add the config field to the appropriate struct in src/config/ (e.g., EditorConfig in src/config/editor.rs) (
src/config/editor.rs) - Parse the option from the Lua config in src/config/mod.rs during config load (
src/config/mod.rs) - Use the parsed config value in the relevant module (ui, editor, plugin, etc.) (
src/main.rs)
🔧Why these technologies
- Rust — Memory safety, performance, and single-binary distribution for a terminal editor with minimal overhead
- Lua (mlua crate) — Lightweight, sandboxed scripting language for user plugins without exposing editor internals unsafely
- Workspace with kaolinite subcrate — Separates core document/text logic (reusable library) from UI and editor bindings for modularity and testability
- Crossterm or similar TUI framework — Cross-platform terminal rendering without ncurses dependency; enables raw mode input and direct screen control
⚖️Trade-offs already made
-
Lua plugins over native Rust plugins
- Why: Simpler distribution and user adoption; no compilation required
- Consequence: Plugin performance is lower than native code; API surface must be carefully designed to avoid unsafe Rust exposure
-
Single-threaded event loop with blocking file I/O
- Why: Simpler logic; most editor operations are fast enough
- Consequence: Large file operations or network plugins may freeze the UI; PTY reads may block
-
Store document history in memory (undo/redo)
- Why: Instant undo/redo responsiveness
- Consequence: Memory usage grows with edit history; very large documents with deep undo stacks consume RAM
🚫Non-goals (don't propose these)
- Real-time collaborative editing (no OT/CRDT)
- Language server protocol (LSP) integration (delegated to plugins)
- GUI version (terminal-only)
- Built-in terminal emulator (PTY support is minimal; not a primary use case)
🪤Traps & gotchas
Lua vendoring: mlua is built with vendored feature, bundling Lua 5.4 into the binary—increases size but avoids system Lua dependency issues. Config path expectations: Editor likely looks for ~/.oxrc by default; override mechanism unclear from file listing. Unix-only features: Terminal/PTY features (ptyprocess, nix, mio) only on non-Windows; some plugins may fail gracefully on Windows. No explicit hot-reload: Lua plugins likely require editor restart to reload; watch this if adding dev-mode auto-reload. Test data edge cases: kaolinite/tests/data/ includes no_eol.txt (file without trailing newline) and unicode.txt—be aware these edge cases are tested and regressions here matter.
🏗️Architecture
💡Concepts to learn
- TUI (Text User Interface) — Ox runs entirely in the terminal without a graphical window—understanding cursor positioning, color codes, and terminal event handling via
crosstermis fundamental to all UI work - Cursor-based document model — Ox's architecture centers on mutable cursor positions and line/character indexing (see
document/cursor.rs,document/lines.rs); this differs from rope/tree models and affects performance and undo behavior - Multi-cursor editing — Highlighted in README as a key feature; requires tracking multiple cursor states simultaneously and applying edits atomically across all cursors—complex state management in
document/editing.rs - Lua FFI (Foreign Function Interface) via mlua — Plugins are written in Lua but run in-process via
mlua; understanding how Rust functions are exposed to Lua (and vice versa) is critical for extending the editor - Undo/redo stack (command pattern) — Every edit operation must be reversible;
document/editing.rsimplements an undo/redo mechanism that stores commands—understanding this is essential for adding new editing operations - ANSI escape codes / terminal control sequences — Ox uses
crosstermto abstract terminal colors and cursor positioning; low-level understanding of ANSI codes helps debug rendering issues and terminal compatibility problems - Regex-based search/replace — The
searching.rsmodule uses theregexcrate for pattern matching; understanding regex semantics is important for search/replace feature completeness and performance
🔗Related repos
vim/vim— Dominant terminal editor that Ox explicitly avoids mimicking; understanding Vim's modal model helps appreciate Ox's alternative design philosophyzyedidia/micro— Another Rust-friendly terminal editor with mouse support and simplicity goals; direct competitor in the lightweight TUI editor spaceneovim/neovim— Modern Vim fork with Lua scripting (like Ox's plugin model); architectural comparison point for how Lua integration works in editorscrossterm-rs/crossterm— Direct dependency providing cross-platform terminal control; understanding its API is key to modifying Ox's UI renderingsharkdp/bat— Terminal syntax highlighter (uses similar Rust TUI stack); useful reference for syntax highlighting patterns in Rust terminals
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for Lua plugin system in kaolinite/tests
The repo has a sophisticated Lua plugin system (mlua dependency, plugins/ directory with multiple .lua files) but kaolinite/tests/test.rs only contains basic document tests. There are no tests verifying Lua plugin loading, script execution, or the plugin API. This is critical for ensuring plugins like ai.lua, git.lua, and discord_rpc.lua work correctly.
- [ ] Create kaolinite/tests/lua_plugins_test.rs to test plugin loading from plugins/ directory
- [ ] Add test cases for Lua API bindings (document manipulation, UI events, command registration)
- [ ] Test plugin initialization with the main Lua configuration (.oxrc in config/)
- [ ] Verify that plugins can hook into editor events (kaolinite/src/event.rs)
Add GitHub Actions workflow for testing cross-platform builds and plugin compatibility
The .github/workflows/ci.yml and deploy.yml exist, but there's no explicit matrix testing for the platform-specific dependencies (ptyprocess, mio, nix are only for non-Windows). The repo should verify builds succeed on Linux, macOS, and Windows, and that plugin tests pass on each platform.
- [ ] Extend .github/workflows/ci.yml with matrix strategy for [ubuntu-latest, macos-latest, windows-latest]
- [ ] Add explicit test step for kaolinite workspace (cargo test --manifest-path kaolinite/Cargo.toml)
- [ ] Add cargo build step with --no-default-features for Windows to catch platform-specific compilation errors
- [ ] Document which workflows test plugin system and configuration loading
Add comprehensive documentation for the Lua plugin API in a PLUGIN_DEVELOPMENT.md file
The repo ships with 10+ plugins (ai.lua, autoindent.lua, pairs.lua, etc.) showing the plugin system is mature, but there's no documented API guide. New contributors cannot understand how to create plugins or extend the editor. The plugins/ directory serves as implicit documentation.
- [ ] Create PLUGIN_DEVELOPMENT.md documenting the Lua API exposed by kaolinite (from kaolinite/src/lib.rs and event handlers)
- [ ] Reference kaolinite/src/event.rs to list available event types plugins can hook into
- [ ] Include code examples from existing plugins (plugins/quickcomment.lua, plugins/pairs.lua) as reference implementations
- [ ] Document how plugins interact with src/config/mod.rs configuration system and keybinding registration (src/config/keys.rs)
🌿Good first issues
- Add integration test for multi-cursor undo/redo in
kaolinite/tests/test.rs. Filekaolinite/src/document/editing.rshas undo logic, but it's unclear if multi-cursor state is preserved on redo—write a test and fix if broken.: Tests increase maintainability; multi-cursor is a highlight feature per README, so ensuring it's rock-solid matters. - Document the Lua plugin API by extracting all
mluabindings from mainsrc/(implied to exist) and creating a markdown guide in docs/ or README. Cross-reference against existing plugins inplugins/to ensure completeness.: README mentions a wiki, but this repo has no local plugin API docs; contributors writing plugins will need a reference. - Add a simple
plugins/readonly_mode.luaplugin that prevents edits and shows a status message. Use patterns fromplugins/quickcomment.luaandplugins/autoindent.lua. This tests the plugin system without complex dependencies.: Demonstrates plugin patterns to newcomers; readonly mode is a common feature request for view-only browsing.
📝Recent commits
Click to expand
Recent commits
6cb11e7— Merge pull request #192 from curlpipe/0.7.7 (curlpipe)cfb43ac— Merge pull request #200 from patch0/dont-search-for-empty-strings (curlpipe)2c6167c— Return early from various search functions when the target is empty (patch0)80fa242— Simplified and improved README.md (curlpipe)dcbcfa7— version bump (curlpipe)4a2ef25— Merge pull request #190 from curlpipe/0.7.6 (curlpipe)a280f47— attempted to fix pasting issues (curlpipe)e5546e2— code cleanup (curlpipe)5ae98c9— Changed around shell field on windows to fail silently (curlpipe)f63a5af— Reintroduced shell field on windows terminal configuration (curlpipe)
🔒Security observations
Ox editor has moderate security concerns primarily related to its plugin system. The use of unrestricted Lua script execution (mlua with vendored Lua 5.4) combined with access to file operations, shell execution (ptyprocess), and networking
- High · Lua Script Execution Without Sandboxing —
src/plugin/run.lua, src/plugin/bootstrap.lua, plugins/. The codebase uses mlua (Lua 5.4) to execute Lua scripts from the plugins directory. The plugin system loads and executes arbitrary Lua code (ai.lua, discord_rpc.lua, git.lua, etc.) without apparent sandboxing or capability restrictions. This allows plugins to potentially access file system, execute system commands, or access sensitive data through Lua's native libraries. Fix: Implement Lua sandboxing by restricting access to dangerous standard libraries (os, io, debug). Create a restricted environment with only necessary APIs. Consider signing or validating plugins before execution. Document plugin security model clearly. - High · Shell Command Execution via PTY Process —
Cargo.toml (ptyprocess dependency), src/editor/. The codebase uses ptyprocess for terminal interaction (ptyprocess = 0.4.1). Combined with plugin capabilities (git.lua, etc.), there's potential for arbitrary shell command execution if user input or plugin code is not properly sanitized before being passed to shell operations. Fix: Validate and sanitize all inputs before passing to shell operations. Use allowlists for executable paths. Implement proper argument quoting and escaping. Consider using safer alternatives to shell execution when possible. - Medium · Unvalidated File Operations —
kaolinite/src/document/disk.rs, src/editor/documents.rs. The file system operations in kaolinite/src/document/disk.rs handle file reading/writing without explicit validation of file paths. Combined with Lua plugin execution, malicious plugins could potentially perform unauthorized file operations or access sensitive system files. Fix: Implement path canonicalization and validation. Restrict file operations to intended directories. Use a file access control list if plugins can trigger file operations. Validate all file paths against a whitelist policy. - Medium · Networking Without Explicit Security Controls —
src/plugin/networking.lua, plugins/discord_rpc.lua. The src/plugin/networking.lua file suggests plugin capability for network operations. There's no visible authentication, encryption, or validation of network endpoints, which could enable SSRF attacks or data exfiltration through plugins. Fix: Implement network policy controls for plugins. Require explicit user approval for network access. Validate all URLs and endpoints. Use certificate pinning for critical connections. Log all network operations. - Medium · External Configuration Files Without Validation —
config/.oxrc, config/minimal.lua, src/config/. The config/.oxrc and config/minimal.lua files are loaded and processed. The README indicates configuration is user-editable, but there's unclear validation of config values, especially for settings that affect security (keybindings, file paths, external commands). Fix: Implement strict schema validation for configuration files. Validate data types and value ranges. Sanitize all configuration inputs. Use safe defaults. Consider using a secure config format with validation. - Low · Base64 Dependency Without Clear Purpose —
Cargo.toml (base64 = "0.22.1"). The base64 crate is included but its usage is unclear from the file structure. If used for encoding sensitive data, it could provide false sense of security (base64 is encoding, not encryption). Fix: Audit actual usage of base64 in the codebase. If encoding secrets, switch to proper encryption. Document the purpose of base64 encoding. Consider if it's truly necessary. - Low · Vendored Lua Library —
Cargo.toml (mlua with vendored feature). The mlua dependency uses 'vendored' feature which embeds Lua 5.4. While this reduces supply chain risk for Lua itself, it increases the binary size and may complicate security patching of the embedded Lua version. Fix: Monitor Lua 5.4 security advisories and update vendored version promptly. Consider security implications of embedding vs. system Lua. Document the vendored dependency in security documentation.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.