Design notes
- Local-first: files and commands run in the workspace
- Single runtime: Agent, Session, ToolRegistry, Provider share one semantics
- Cache-first: stable content first, volatile last
- Structured edits: Search/Replace diffs, validate then write
Local coding agent workbench: read the project, edit files, run commands, preview results — with byte-level optimization for the LLM prefix cache.
| Component | Minimum Version | Purpose |
|---|---|---|
| Node.js | 20.19+ | Runtime and package management |
| npm | 9+ | Dependency management |
| Rust toolchain + Cargo | stable | Desktop build (debug/release/publish) |
| .NET SDK | - | C# Roslyn analyzer (required for release builds) |
npm run build runs build:host-server to compile codepapr-server, so it requires the Rust toolchain. Only narrow commands such as npm run lint or the pure-vitest part of npm run test avoid Rust.
# After cloning the repository
npm install
npm run build
The desktop build (cargo check / npm run debug / release / publish) pulls tree-sitter and language grammars from crates.io; it no longer depends on .cargo-vendor/* submodules. npm run build already compiles the codepapr-server host, leaving a usable host binary on disk; when the desktop starts, it launches that binary as a Tauri externalBin sidecar.
npm run verify
Passing this step confirms that your machine at least satisfies: correctly installed Node dependencies, successful workspace build (including the codepapr-server compile), passing workspace tests, and passing Tauri cargo check.
| Platform | Architecture | Status |
|---|---|---|
| macOS | arm64 (Apple Silicon) | Supported (outputs .dmg installer) |
| Windows | x64 | Supported (outputs .msi installer) |
Both platforms share the same Rust backend and frontend codebase; the release pipeline outputs dmg/msi installers simultaneously.
Depending on your operations, you may also need:
| Command | Purpose |
|---|---|
npm run debug | Development debugging with hot reload; suitable for long sessions and daily use |
npm run release | Directly launch the optimized desktop runtime (no installer packaging) |
npm run publish | Generate platform installer (.dmg / .msi) and organize into Release/ |
| Level | Path | Purpose |
|---|---|---|
| App-level | ~/.codepapr/codepapr.sqlite | Provider, model, API key, language, sampling parameters |
| Project-level | <workspace>/.CodePapr/ | Project state, session records, rules, Agents, Skills |
| Mode | Description | Use Case |
|---|---|---|
deepseek | DeepSeek official provider | Recommended default; best cache optimization |
openai | OpenAI-compatible format | Connecting to OpenAI or compatible services |
claude | Claude/Anthropic-compatible format | Connecting to Claude or compatible endpoints |
# OpenAI format (used by DeepSeek provider by default)
https://api.deepseek.com/v1
CodePapr's DeepSeek provider always uses the OpenAI-compatible https://api.deepseek.com/v1. If you want to use the Anthropic protocol with DeepSeek, select Claude as the provider and set baseURL to DeepSeek's Anthropic-compatible endpoint.
The desktop provider compatibility layer reads API keys in the following order:
DEEPSEEK_API_KEYOPENAI_API_KEYANTHROPIC_API_KEYdeepseek-flash)| Scenario | Model Used | Temperature |
|---|---|---|
| Main Agent conversation | Primary model (default deepseek-v4-pro) | Default |
| Context compression (internal Compactor agent) | compactionModel tier (default fast model deepseek-flash, switchable to primary) | 0.1 |
| Sub-agent dispatch (heavy/execution type) | Primary model | User configured |
| Sub-agent dispatch (Explore/Scout fast mode) | Fast model (switchable to primary) | User configured |
Slash commands declaring model: fast (e.g. /search, /lint, /clean, /commit, /summary) | Fast model (falls back to primary if not enabled) | 0.3 |
General / LLM / Search / Sub-agents / Advanced / App. Voice lives on the character panel.
npm install
npm run build
npm run debug
| Entry Point | Best For |
|---|---|
| Desktop Workbench | Long sessions, file tree, Git, preview, browser interaction — a visual workbench |
Note: The three built-in sub-agents — Explore, Scout, and Mentor — can be enabled and configured in the desktop settings panel (Mentor tab); the internal Verifier / Compactor model tiers are configured in the Advanced tab (verifierModelTier / compactionModel) and are never exposed via the task tool.
Ask, Plan, Agent, and App are not different products but four working modes of the same Runtime.
Best for: Explaining architecture, clarifying module responsibilities, analyzing error causes, asking questions before deciding whether to execute.
Characteristics:
Best for: Producing execution plans before large changes, confirming affected files and verification approach, breaking complex tasks into clear steps.
Characteristics:
question tool to clarify decisions with the userBest for: Fixing bugs, implementing features, running tests and verification, tasks that require actual file read/write and tool invocation.
Characteristics:
bash display execution status and logs in tool call cardsBest for: Data exploration and visualization, generating interactive charts and dashboards, turning analysis results into interactive apps with a single sentence.
Core Philosophy:
Workflow:
.CodePapr/apps/<appId>/app_render({ appId }) to mount it in the right-side Application panel (does not write files)App conventions:
sandbox="allow-scripts allow-same-origin")window.papr) to call Agent, storage, HTTP, and filesystem capabilitiesinbox in the manifest and subscribe with papr.events.on(channel, cb) — the contract is copied into session context "## Enabled plugins"; Agent mode calls app_publish from that catalog (do not use app_list); history replays via papr.db.get('inbox:<channel>'). Self-refreshing widgets must not declare inbox.papr.agent.run uses a 300-second idle timeout: as long as the Agent keeps emitting progress events (streaming output / tool calls) it can run indefinitely; only 300s of total silence triggers a timeout. Tool rounds are bounded by maxToolRounds (default/cap 50; search calls count toward the total)app_render({ appId }) again to refresh — supports iterative refinementSession Isolation:
Model Strategy: Always uses the primary model to ensure app generation quality.
App Management: The right panel's "Apps" tab shows all registered .papr apps. Green/red dots indicate running status. Bottom toolbar: ▶ Start / Open / ■ Stop / 🗑 Delete. LLM manages app lifecycle via app_list, app_start, app_stop, app_delete tools. For full development and plugin specifications, see the App Mode & Plugin Generation section.
Permission model: Apps declare access with local (none / read / write) × network (true / false). Settings → App Tab can narrow the global default and per-app overrides; saving restarts running backends with the new sandbox.
CodePapr's actual performance depends heavily on task description quality. The most effective prompts typically include:
Fix the issue in packages/@codepapr/ui where background processes aren't stopped after preview closes.
First find the binding logic between the current preview session and background processes, then make a minimal fix.
After the change, at least run verification for the affected scope; if no narrow verification exists, explain why.
Help me fix the preview.
Click Review in the top AgentOps toolbar to open the Code Review panel:
HEAD~1..HEADA compact indicator bar on the right edge of the chat area shows one tick per user message:
#1 number + user's first sentence)The toolbar search box supports both conversation and file search via Chat | Files tabs:
↑↓ navigate Enter jumpThe desktop uses non-blocking toasts instead of alerts:
info / success / warning / errorerror defaults to 8 secondsWhen the Agent requests to read or list absolute paths outside the project, the desktop shows a permission dialog:
Authorization results are saved in a whitelist; subsequent accesses to the same path won't trigger the dialog again. Write, edit, and command execution remain restricted to the workspace.
Before each user message, CodePapr captures a code snapshot via its own internal Shadow Git repo at .CodePapr/git/ (powered by libgit2 — no system Git CLI required):
.gitignore and auto-excluding node_modules/, dist/, .next/, large files (>100MB), etc.index.add_path and committed as checkpoint #N · "message preview"When you need to roll back:
refs/codepapr-backup-before-reset is created automatically — you can undo the reset anytimeThe Agent registers a comprehensive toolset covering file operations, ProjectGraph analysis, Git, preview, browser, Shell, LSP, and all local development scenarios. Below are the key tools grouped by capability.
A unified project semantic graph tool that selects operations via the action parameter. Simultaneously returns a directory tree, code structure skeleton, and file/symbol relationship graph, serving as the foundation for all symbol lookup, dependency analysis, and impact analysis.
| Tool / Action | Capability |
|---|---|
graph full | Generate full ProjectGraph: directory tree + code structure skeleton + dependency graph |
graph overview | Lightweight overview (no full code skeleton); good for quickly perceiving project shape |
graph lookup | Look up symbols by name/path; returns symbolId, file, and line number |
graph dependency | Extract dependency subgraph; supports incoming / outgoing / both |
graph entrypoints | Find project entry files and entry symbols |
graph impact | Reverse impact analysis: what would be affected by modifying a given symbol |
graph implementations | Find implementations/derived symbols of an interface or base class |
graph smart_context | Intelligently retrieve the most relevant project context based on a task description |
graph dead_code | Detect unused symbols (classes, functions, variables) |
graph circular_deps | Detect circular import dependencies between files |
graph type_hierarchy | Build inheritance/implementation hierarchy tree for classes, interfaces, and types |
graph suggest_refactors | Based on code structure analysis, suggest extractable methods and symbols that could become standalone files |
graph test_impact | Analyze which existing tests would be affected by a list of changed files |
graph generate_tests | Auto-generate test skeletons for exported testable symbols in the project |
| Tool | Capability |
|---|---|
read | Read file content; supports line ranges, line windows, context lines, and byte limits |
write | Create or fully overwrite a file; use edit for partial modifications |
edit | Single-file precise SEARCH/REPLACE modification; search must exactly match source file |
patch | Multi-file atomic SEARCH/REPLACE; all blocks validated successfully before writing together; any failure rolls back all |
grep | Regex search file contents; returns match locations with context; semantic:true switches to LSP semantic search |
glob | Search project files by filename glob patterns; supports regex union |
list | Browse project directory tree, embeds lightweight per-file symbols (AST); no-AST languages return path only |
| Tool / Action | Capability |
|---|---|
lsp definition / references | Language service read-only navigation: jump to definition, find all references |
lsp_edit rename / code_action / format | Language service semantic edits: rename, code actions, formatting |
diagnostics | Single-file LSP diagnostics or project-level lint / typecheck |
| Tool / Action | Capability |
|---|---|
bash run / list / stop / stop_all | Run shell commands in the project (through a shell; pipes/&&/variables supported); blocks by default, background:true runs in background returning a pid, workdir sets the working directory; list/stop/stop_all manage background processes |
| Tool / Action | Capability |
|---|---|
git status / diff / log | Read workspace status, diff, and commit history |
git branch / stage / commit | Switch or create branches, stage changes, create commits |
git restore / reset | Restore changes or safe rollback (auto-creates backup branch and snapshot) |
| Tool / Action | Capability |
|---|---|
browser open / navigate / reload / close | Built-in browser: open URL, navigate, refresh, close |
browser click / type / read / screenshot / get | Browser interaction: click elements, type text, read DOM, screenshot, read state |
| Tool | Capability |
|---|---|
app_render | Open a .papr App already on disk into the Application panel. Pass appId only. Write manifest.json and the entry HTML with write/edit/patch under .CodePapr/apps/<appId>/ first. Access lives in the manifest (local/network; legacy level 0-3 still works). HTML uses window.papr SDK. Call again after edits to refresh. |
app_list | List all registered .papr apps (name, kind, pinned, has backend, is running, inbox). App mode only: call before creating to check for duplicates. Coding-Agent publish contracts live in session context, not this tool. |
app_start | Start backend service by appId. Checks port availability, turns status green. |
app_stop | Stop backend service by appId. Turns status red. |
app_delete | Delete app by appId. Stops backend, removes files, clears storage. Irreversible. |
app_publish | Push content to an app/plugin channel (app_publish({ appId, channel, payload })). Only publish to targets listed in session context "## Enabled plugins" (enabled + declared inbox); do not call app_list first. Events are appended atomically (concurrency-safe, last 200 kept) and delivered live via papr://event when the app is mounted; when unmounted they are briefly queued (~30s) so a shortly-opening app still receives them live. Canvas/kanban: after analysis → push a scene or a card using the example. |
| Tool | Capability |
|---|---|
websearch | Online web search, aggregating multi-source results |
webfetch | Read web page content, auto-extracting body text and converting to plain text; save: true downloads raw content to the project and returns the path |
| Tool | Capability |
|---|---|
skill | Load Skill instruction files from the project's .CodePapr/skills/ directory |
local_time_now | Get current local time, date, and timezone; suitable for time-sensitive queries (market open/close, event deadlines, etc.) |
question | Ask the user questions in Plan mode; supports predefined options and multi-select |
task | Delegate sub-tasks to declarative sub-agents (Explore / Scout / Mentor) for execution |
todo | Plan and track multi-step task checklists; supports initialization, progress reporting, and re-planning |
In the desktop, read / list operations on absolute paths outside the project trigger a PermissionDialog popup for authorization; writes remain restricted to the workspace. For a file directly under the filesystem root, choosing "Allow this folder" is automatically downgraded to granting that single file only, so one click can never grant the entire filesystem root.
A single read / write / edit / patch operation is capped at 20MB, covering most source code and binary resource files, though large files will significantly increase token consumption.
tools config allowlists. For code modifications, prefer edit/patch via Search/Replace Diff; use write only for new files. For command execution, use bash uniformly: short commands via bash(command: ...), long-lived processes via bash(command: ..., background: true), and manage background processes via bash(action: list/stop). For web access, use websearch (search) and webfetch (read pages; save: true to download files); opening in the system browser uses bash.
Experimental feature, off by default: enable "Characters" under Settings → General → Experimental features to reveal the toolbar entry. CodePapr supports creating, importing, and managing AI characters, allowing the Agent to converse with you in a specific persona. Once enabled, the profile is injected into the Session Bootstrap (assembled in promptBuilders.ts / characterTypes.ts), not core promptSystem.ts and not ImmutablePrefix.
Each character includes the following fields:
| Field | Description |
|---|---|
| Name | Character display name |
| Avatar | Uploaded image, also shown in the chat interface |
| Description | Appearance, backstory, identity setting |
| Personality | Speaking style, character traits, behavioral habits |
| Scenario | The situation in which the current conversation takes place |
| First Message | What the character would say in their first conversation |
| Example Dialogues | Multiple dialogue groups separated by <START>, guiding the LLM to understand the character's style |
| System Prompt | Additional instructions appended after the character persona |
| Tags | Custom tags for categorization and search |
In roleplay mode, the system prompt specifies the following format rules so TTS can correctly distinguish dialogue from actions. In Ask / Plan modes the character is always injected as a coding persona and this format does not apply:
| Format | Meaning | TTS Behavior |
|---|---|---|
*Action description* | Narration, scene description, character actions | Not spoken |
| Plain text | Character speech | Spoken |
**Bold text** | Emphasis, stress | Spoken with emphasis |
(Parentheses) or (whisper) | Tone cues | Not spoken |
CodePapr is compatible with the chara-card-v3 specification and can import characters from other tools:
Supported PNG chunk keywords: chara, ccv3, character, character_card
Click a character's Export button in the character list to export it as a PNG character card. The PNG embeds the complete CCv3 JSON and can be used in tools like SillyTavern. Portable voice settings (speed, sample steps, sentences per chunk, playback mode, languages) are written to extensions.codepapr.voice; local reference-audio and fine-tuned-model file paths are not exported with the card.
Click Enable on the editor to apply the character to the current session only; unsaved edits in the panel are saved automatically first. Clicking a name in the list opens it for editing and does not activate it. Opening the panel selects the character already enabled for this session. In an empty session, switching characters replaces the previous character's greeting with the new one.
Character personas are placed in the Session Bootstrap (not in the system prompt's ImmutablePrefix), so switching characters does not break the LLM prefix cache. In Ask / Plan modes the character is always injected as a coding persona; the roleplay format only applies in Agent mode. New sessions start with no character.
Experimental feature, off by default: enable "Voice" under Settings → General → Experimental features to reveal voice controls; auto-read also requires "Characters" enabled with voice configured on the active character. CodePapr integrates the GPT-SoVITS voice cloning engine, capable of synthesizing a character's text replies into speech locally. Only 3-10 seconds of reference audio are needed to clone a character's voice.
First-time voice usage requires installing GPT-SoVITS. There are two installation entry points:
The installation wizard auto-completes 5 steps: check Python → clone GPT-SoVITS repository → pip install dependencies → download pretrained models (about 2GB, using hf-mirror source) → verify.
Requires Python 3.10+ already installed on the system. The installation process writes to ~/.codepapr/gpt-sovits/.
ws-batch; streamed-pipeline / streamed-pcm / whole also selectableThe Voice Tab exposes four playback modes. The default and recommended one is WebSocket batch streaming (ws-batch): sentences are first merged into chunks per the "Merge Sentences" setting (3 by default), then each chunk is sent over a single persistent WebSocket connection and returned one by one, with first-word latency around 1-2 seconds and smooth inter-sentence transitions.
The other three: streamed-pipeline / streamed-pcm (per-sentence HTTP requests with PCM pushed straight to the player; best compatibility) and whole (waits for the complete reply, then synthesizes and plays it in one go; slowest start but the most coherent).
For higher audio quality requirements, use the fine-tuning feature in the Voice Tab:
Project-wide rules are injected into the main Agent and all sub-agents. Good for:
.CodePapr/AGENTS.md and merges it into the stable system prompt. Missing files are silently skipped.
Cross-session memory is a single file in your workspace, .CodePapr/MEMORY.md (three sections: user preferences & constraints / tech stack & environment / architecture & known facts) — readable, diffable, git-friendly. The built-in memory curator (internal subagent) maintains it in the background, and the memory panel is its editor. Layers and timing: Context layering.
memory_write / memory_search / memory_list / memory_forget are retired; direct writes to MEMORY.md are intercepted and rejected — the Agent states durable facts in its answer instead.Manually trigger v4 skeleton compaction, folding older rounds into a checkpoint to free token space:
The "Config" entry in the desktop project header can:
.CodePapr/AGENTS.md (generates a default template if none exists).CodePapr/agents/*.md).CodePapr/skills/**/SKILL.md)| Path | Purpose |
|---|---|
~/.codepapr/codepapr.sqlite | App-level settings, sessions, and cache statistics |
~/.codepapr/lsp-tools/ | Managed LSP tool download cache (downloaded on first need, reused afterwards) |
<workspace>/.CodePapr/project.sqlite | Project-level state, chat history, cache statistics |
<workspace>/.CodePapr/MEMORY.md | Cross-session project memory (maintained by the memory curator; editable in the panel; injected into session bootstrap every turn) |
<workspace>/.CodePapr/skills | Project-level skill files |
<workspace>/.CodePapr/agents | Project-level sub-agent definitions |
<workspace>/.CodePapr/commands | Project-level custom commands |
<workspace>/.CodePapr/downloads/ | Default download directory for the Scout sub-agent |
~/.codepapr/voices/ | Character reference audio files |
~/.codepapr/gpt-sovits/ | GPT-SoVITS installation and pretrained models |
CodePapr's automated modifications do not rely on standard Git diff line numbers. Multiple localized modifications are preferentially generated as Search/Replace blocks:
<<<<<<< SEARCH
Existing code already in the file
=======
Replacement new code
>>>>>>> REPLACE
SEARCH must exactly match content in the target fileSEARCH matches multiple locations, it is rejected to prevent unintended changesA Skill is the main Agent's reusable operations manual, suitable for codifying search strategies, troubleshooting workflows, release checklists, review manifests, and project-specific working methods. It does not create an independent sub-agent but serves as project-level context for the model to select on demand.
Organized as directory packages, placed under .CodePapr/skills/**/SKILL.md. Each directory can contain assets/, references/, scripts/, and other resources.
---
name: search
description: Conduct verifiable searches using public web, official docs, and community resources
---
# Search Skill
When a task requires public information, current facts, third-party API usage, or error troubleshooting:
- Official docs first, then GitHub issues/PRs, then community answers.
- Use double quotes for exact error strings, e.g. "Cannot find module".
- Limit to specific sites using site:, e.g. site:developer.mozilla.org fetch abort.
- Include the library name, version, runtime environment, and key error codes together.
skill called to read the full content.CodePapr/project.sqliteThe default search Skill includes common reference sources and methods:
site: to scope to a domain, double quotes for exact errors, package name plus version numberCodePapr comes with three built-in sub-agents that the main Agent can dispatch via the task tool without additional configuration:
| Agent | Purpose | Model | Tools |
|---|---|---|---|
| explore | Read-only code analysis: search project files, locate symbols, analyze dependencies | fast | read, read_image, list, lsp, diagnostics, grep |
| scout | Web search: find documentation, API references, latest resources | fast | websearch, webfetch, browser, read_image |
| mentor | High-level architecture/algorithm/debugging guidance (no code writing, no tool usage) | mentor* | None |
* Mentor uses the primary model by default; an independent mentor model can be enabled in settings (supports independent API Key, Base URL, and model selection; falls back to the main API Key when no dedicated key is configured).
| Agent | Purpose | Model | Tools |
|---|---|---|---|
| verifier | Goal acceptance: read-only audit of whether the Worker truly achieved the goal — anti-completion-bias, anti-forgery (/goal) | verifierModelTier (fast/primary/mentor) | read, grep, glob, list |
| compactor | Second-level summary for compaction: merges the skeleton into one summary only when it still exceeds the budget (shared by between-turn / mid-loop / Goal / task sub-agents) | compactionModel (fast/primary) | None (pure reasoning) |
All three internal agents are internal: true, invoked directly by the runtime: Verifier by the GoalRunner acceptance loop (dedicated budget: 6 tool rounds / 3-minute wall clock); Compactor by the compaction pipeline when the skeleton still overflows; Memory-curator by the memory pipeline at the delivery / pre-compaction checkpoints (its material never contains raw tool output). All three are zero-tool and get no skills/memory/project-graph injection (bootstrap isolation), with the sub-agent default 20-minute wall clock. In v4 the main compaction path is the deterministic skeleton (zero LLM); the Compactor runs only as a single second-level summary, falling back to deterministic line truncation when the fast tier is selected but the fast model is disabled — never recursion.
Declare a sub-agent in .CodePapr/agents/<name>.md with YAML frontmatter + body. The main agent can delegate subtasks to it. An agent with the same name will override the built-in definition.
---
description: reviewer is responsible for reviewing current changes, identifying risks, and providing minimal fix suggestions
mode: subagent
model: fast
temperature: 0.2
tools:
read: true
grep: true
diagnostics: true
git: true
write: false
exec: false
---
You are reviewer, a read-only code review sub-agent.
Responsibilities:
- Read the goal, relevant files, and current diff delegated by the main agent.
- Prioritize finding real bugs, behavioral regressions, missing edge-case handling, and absent verification.
- Provide minimal fix suggestions, indicating which files to modify and what verification commands to run.
Boundaries:
- Do not directly modify files by default.
- Do not repeatedly summarize irrelevant code style; only report findings that affect correctness, reliability, or maintainability.
Output Format:
1. Findings: List issues by severity
2. Suggested Fix: Provide the minimal fix direction
3. Verification: List recommended verification commands
model: Override model; options: fast (fast model) or a specific model nametemperature: Temperature parameter; optional numeric valuetools: Tool switches; defaults to inheriting all tools; declaring an empty object {} means no tools.md) is the sub-agent name; same name overrides built-in agentsdescription to tell the main agent when to invoke ittools to control read/write/command permissions| Approach | Trigger | Description |
|---|---|---|
| Orchestration-layer auto-decomposition | System auto-decision | In Agent mode, when a task contains execution verbs and is sufficiently complex, the LLM decides whether to break it into 2-5 sub-tasks for parallel/serial execution |
| Task tool active delegation | Agent actively invokes | The main Agent explicitly calls the task tool during reasoning to delegate a sub-task to an independent sub-agent (including built-in and custom) |
.CodePapr/AGENTS.md contains global project rules inherited by all modes and all sub-agents; custom Agents are dedicated sub-agents, only activated when the main Agent delegates sub-tasks via the task tool. The former is for writing "what all tasks must comply with," the latter for "who handles a certain type of task and which tools they can use."
Commands support both --name (recommended) and /name (legacy compatibility) formats. A command's model field determines routing: undeclared uses the primary model, fast uses the fast model, and local commands cost zero tokens.
| Command | Function | Model | Example |
|---|---|---|---|
/help | List all commands and descriptions | Local | /help |
/commands | Alias for /help | Local | /commands |
/compact | Force-compress current session context — deterministic skeleton checkpoint (zero LLM; one second-level summary only if the skeleton still overflows) | Primary / Fast | /compact |
/undo | Undo the last conversation reset (restore truncated messages and code snapshot) | Local | /undo |
/goal | Autonomous loop: Worker executes + Verifier validates, until condition is met | Primary | /goal exec:npm test |
/review | Review current changes or specified scope | Primary | /review src/App.tsx |
/fix | Locate and fix a specified issue | Primary | /fix Login button not responding |
/test | Add tests or run relevant tests | Primary | /test src/utils/format.ts |
/explain | Explain a file, symbol, error, or implementation | Primary | /explain handleSubmit function |
/diagnose | Diagnose errors, slow operations, or abnormal behavior | Primary | /diagnose Page load exceeds 5 seconds |
/refactor | Reorganize code while preserving behavior | Primary | /refactor src/components/Modal.tsx |
/doc | Update documentation for changes or features | Primary | /doc New refund endpoint |
/new | Create new files, components, or features from scratch based on description | Primary | /new Create user password reset REST API |
/optimize | Analyze and fix performance bottlenecks | Primary | /optimize src/pages/Dashboard.tsx |
/build | Build the project and diagnose/fix build errors | Primary | /build |
/search | Search codebase for patterns, usages, definitions, or references | Fast | /search auth middleware |
/lint | Run linter and fix violations | Fast | /lint src/ |
/clean | Clean up dead code, unused imports, and leftover debug statements | Fast | /clean src/utils/ |
/commit | Stage changes and generate a well-formed commit message | Fast | /commit |
/summary | Provide a high-level overview of a file, module, or entire project | Fast | /summary src/core/ |
Declare reusable prompt templates in .CodePapr/commands/<name>.md to register slash commands /<name>:
| Syntax / Placeholder | Description |
|---|---|
$ARGUMENTS | All arguments entered by user after the command |
$1 $2 ... | The Nth positional argument (supports quoted values) |
@path | Read relative workspace file content and embed as an inline code block |
!`cmd` | Execute simple shell command and embed output (simple commands only, no compound operators) |
Example 1: Static Page & Rendering Logic Diagnosis (Zero Git Risk)
---
description: Diagnose index.html structure and visual logic
usage: /pagecheck [observed issue]
model: fast
---
Please help diagnose the page structure and visual logic of this static project.
Page entrypoint: @index.html
User question: $ARGUMENTS
Example 2: Dependency & Script Analysis
---
description: Analyze package.json dependencies and scripts
model: fast
---
Please answer user question based on root config:
Config: @package.json
Question: $ARGUMENTS
Example 3: Code Review & Lint Fix (Delegate to Subagent + Live Status)
---
description: Review and fix lint
agent: code-reviewer
---
Please review the changes for $ARGUMENTS and fix any lint issues.
See rules at @.CodePapr/AGENTS.md
Current status: !`git status -s`
/ in the chat input to bring up the command palette with ↑↓ navigation; type /command-name args to run. Type /help in chat to see all registered project commands.
In CodePapr, App mode is not merely a code assistant — it is an on-demand interactive application factory. Simply describe what you need in natural language, and the Agent explores data, designs architecture, and builds ready-to-use .papr applications or desktop plugins in seconds, mounting them directly in the main window.
Every .papr app declares its form via the kind field in manifest.json:
| Artifact Form | Manifest Declaration | Runtime Behavior | Typical Use Cases |
|---|---|---|---|
| Fullscreen App (App) | kind: "app" (default) |
Opens as an exclusive fullscreen view over the workbench, dominating the primary viewport. Supports background command processes. | SQLite Database Explorer, 3D topology graphs, multi-panel dashboards, static site documentation previews |
| Desktop Plugin (Plugin) | kind: "plugin" |
Renders as an in-window lightweight overlay (HUD), coexisting with the coding workbench. Always visible while you write code, freely draggable, dynamically resizable via papr.window, and easily pinned/unpinned in the App Dock. |
Real-time crypto/stock tickers, live architecture evolution boards, task progress widgets, scratchpads |
kind: "plugin" plugin.local: "write" project-write access, ensuring safety and lightweight operation.
All apps and plugins are stored in .CodePapr/apps/<appId>/. To allow precise patching and continuous iteration by the Agent, CodePapr mandates modular file organization (native ES Modules, zero build tools, import statements must include .js extensions):
.CodePapr/apps/<appId>/
├── manifest.json # App manifest: metadata, kind, surface, permissions, inbox contracts, agents
├── index.html # Shell HTML: skeletal markup only, loads CSS & js/main.js, no giant monoliths
├── css/
│ └── theme.css # Theming & styling: supports html[data-mode="dark"] & html[data-mode="light"]
├── js/
│ ├── main.js # Entry module: initialization, DOM binding, and event listeners
│ ├── db.js # Key-value storage wrapper (papr.db)
│ ├── ui.js # View rendering, loading states, and animations
│ ├── api.js # External HTTP fetch wrapper (papr.http, optional)
│ └── agent.js # Multi-turn AI Agent wrapper (papr.agent.run, optional)
├── data/ # App-private sandbox filesystem storage (papr.fs, created at runtime)
└── db.sqlite # papr.db data & inbox history (created at runtime)
Note: For lightweight plugins (kind: "plugin"), a 3-file layout (index.html + css/theme.css + js/main.js) is recommended until any single file exceeds ~200 lines.
window.papr)Apps run inside a secure sandboxed iframe. Without installing npm packages, the runtime automatically injects the window.papr SDK:
| SDK Module | Primary APIs | Permission Requirements | Capabilities & Details |
|---|---|---|---|
papr.db |
get(key)set(key, val)delete(key)keys() |
No permissions required (always available) | SQLite-backed persistent key-value storage isolated per app. Data persists across app restarts. |
papr.agent.run |
run({ agent, task }, onProgress?) |
Follows local/network profile |
Invokes a multi-turn AI sub-agent directly within the app. Supports streaming events (tool-call-start, content-delta) and a 300s idle timeout. |
papr.http |
get(url)post(url, body)request(opts) |
network: true |
Safe public HTTP client with header whitelisting. Localhost and private intranet requests are blocked to prevent SSRF. |
papr.fs |
readFile(path)writeFile(path, data)exists(path)list()delete(path) |
No permissions required (app data dir) | Dedicated sandbox filesystem restricted to the app's data/ folder. writeFile auto-creates parent folders; supports base64 binary assets. |
papr.events |
on(channel, callback) |
No permissions required (always available) | Real-time event bus. Subscribes to events pushed by the coding Agent via app_publish; returns an unsubscribe handler. |
papr.window |
setSize({ width, height })getBounds()onBounds(cb) |
No permissions required (kind: "plugin" only) |
Plugin viewport control. Dynamically resizes the overlay content box at runtime (host automatically adds the draggable titlebar). |
papr.app.info |
info() |
No permissions required | Retrieves app metadata: appId, name, version, local, network, and effective permissions. |
app_publish + inbox Contract)In "Agent writes code in terminal → Plugin visualizes progress/architecture in real time" collaboration workflows, CodePapr provides a zero-overhead publish/subscribe system:
inbox channels and minimal payload example in manifest.json.app_publish({ appId, channel, payload }) from any writable mode (Agent / Plan / App).db.sqlite (up to 200 events retained); delivered live via papr://event if mounted; when unmounted events are briefly queued (~30s) so a freshly opening instance still receives them live, while later launches replay history using papr.db.get("inbox:<channel>") (live and replay can overlap — dedupe by seq).manifest.json uses a Local Access (local) × Network Access (network) matrix:
| Access Axis | Value | Allowed Capabilities & Tooling Scope |
|---|---|---|
local |
"none" |
Pure compute sandbox: only papr.db and papr.fs private storage. |
"read" |
Workspace read access: unlocks read-only Agent tools (read, grep, list, lsp). |
|
"write" |
Workspace modification: unlocks Agent writing & execution (write, edit, patch, bash). Note: Plugins cannot use this level. |
|
network |
false |
Strict offline sandbox: CSP blocks all external network requests. |
true |
Network enabled: unlocks papr.http, Agent websearch / webfetch, and MCP services. |
Switch to the Apps tab on the right sidebar to browse all generated .papr apps and plugins:
.zip for sharing and backup.Prompt: "Generate a lightweight floating crypto ticker plugin in the top-right corner, showing BTC/ETH prices every 10s with compact typography."
manifest.json Configuration:
{
"spec": "papr/0.1",
"name": "Crypto Ticker",
"version": "1.0.0",
"kind": "plugin",
"surface": {
"type": "overlay",
"width": 300,
"height": 180,
"position": "top-right"
},
"local": "none",
"network": true
}
js/main.js Logic:
async function fetchPrices() {
try {
const data = await window.papr.http.get('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd&include_24hr_change=true');
render(data);
} catch (err) {
console.error('Ticker error:', err);
}
}
fetchPrices();
setInterval(fetchPrices, 10000);
Prompt: "Generate an architecture evolution board plugin that subscribes to the cards channel to receive live task nodes as you code."
manifest.json Configuration (with inbox contract):
{
"spec": "papr/0.1",
"name": "Architecture Board",
"kind": "plugin",
"surface": {
"type": "overlay",
"width": 360,
"height": 260,
"position": "bottom-right"
},
"local": "none",
"network": false,
"inbox": {
"cards": {
"description": "Push task progress & state change cards",
"example": { "id": "task-1", "title": "Refactor Auth", "status": "done" }
}
}
}
js/main.js Subscription & History Replay:
// 1. Replay historical events on startup
const history = await window.papr.db.get('inbox:cards') || [];
history.forEach(evt => applyCard(evt.payload));
// 2. Listen to live Agent push events
window.papr.events.on('cards', (evt) => {
applyCard(evt.payload);
});
Prompt: "Analyze the stats.sqlite database in this project and generate a fullscreen Database Explorer app with paginated table views and SQL query execution."
The Agent declares local: "read", modularly splits frontend components and SQL result tables, and mounts a full interactive dashboard in the workspace Apps panel.
/goal is a control command (same level as /compact) that starts a Worker + Evaluator dual-model autonomous loop. It transforms the AI coding assistant from a single-turn Q&A mode into a long-running autonomous agent that continues until a machine-verifiable condition is satisfied.
The core mechanism is not adding "keep working until done" to the prompt — it's an engineered self-play system:
The three work together: condition function + Verifier anti-forgery = double insurance. Only when the condition is met AND the Verifier confirms the Worker didn't cheat is it judged SATISFIED.
# Exit code 0 satisfies the condition
/goal exec:npm test
# Exit code 0 AND stdout matches regex
/goal exec:npm test match:"\d+ passed"
# Compound condition, all must pass
/goal exec:npm run lint && exec:npm test
# Natural language goal + verification condition (| separator)
/goal fix auth tests | exec:npm test
| Syntax | Description |
|---|---|
exec:<command> | Execute command, exit code must be 0 |
exec:<cmd> match:"<pattern>" | Exit code 0 AND stdout matches regex pattern |
exec:<cmd1> && exec:<cmd2> | Compound condition, all clauses must pass |
<goal> | exec:<cmd> | Natural language goal + verification condition, separated by | |
.CodePapr/goal-state.md| Limit | Default | Description |
|---|---|---|
| Max iterations | 20 | Maximum outer loop iterations, auto-stops when exceeded |
| Max wall clock | 30 minutes | Wall clock timeout, auto-stops |
| User interrupt | Anytime | "Stop" button on GoalBanner |
| State persistence | Every iteration | Writes to .CodePapr/goal-state.md, prevents context rot |
Configure Goal loop parameters in the Advanced tab of the settings panel:
The Model Context Protocol (MCP) is an open protocol that allows Agents to extend their capabilities through external tool servers. CodePapr includes a built-in MCP host that can connect to multiple MCP servers simultaneously, exposing external tools to the main Agent for invocation.
Each MCP tool is registered in the form mcp__<serverId>__<toolName>, appearing alongside the 30 built-in tools in the ToolRegistry.
| Transport | Description | Use Case |
|---|---|---|
stdio | Subprocess + stdin/stdout JSON-RPC | Local command-line MCP servers (npx / uvx / python, etc.) |
sse | Server-Sent Events | Remote HTTP MCP servers, unidirectional streaming |
streamable-http | Streamable HTTP | Remote HTTP MCP servers, bidirectional streaming |
| Field | Type | Description |
|---|---|---|
name | string | Display name |
category | search / database / custom | Category; search replaces websearch routing when enabled |
transport | stdio / sse / streamable-http | Transport mode |
command / args | string | stdio only: executable command and arguments (arguments support quoted grouping) |
url | string | sse / streamable-http only: HTTP endpoint URL |
env | multi-line KEY=value | stdio only: environment variables; not exposed to model context |
headers | multi-line Header-Name: value | sse / streamable-http only: HTTP request headers, typically for authentication |
allowedTools | comma-separated, supports * wildcard | Allowlist; empty means allow all |
deniedTools | comma-separated, supports * wildcard | Denylist; higher priority than allowlist |
permissionMode | read-only / read-write / dangerous | Permission tier; determines whether confirmation is required before invocation |
requireConfirmation | boolean | Requires confirmation for every invocation |
timeoutSeconds | 5–600 | Per-tool invocation timeout |
The desktop provides three ready-to-use MCP servers by default (all disabled; must be manually enabled):
| Name | Category | Command | Purpose |
|---|---|---|---|
| DuckDuckGo Search MCP | search | npx -y duckduckgo-mcp-server | API-key-free web search |
| Postgres MCP | database | npx -y @modelcontextprotocol/server-postgres <DSN> | SQL queries, schema discovery; write-disabled by default |
| SQLite MCP | database | uvx mcp-server-sqlite --db-path ./database.sqlite | Local SQLite database analysis |
# Name
DuckDuckGo Search MCP
# Transport
stdio
# Command / Arguments
command: npx
args: -y duckduckgo-mcp-server
# Environment variables (one KEY=value per line)
env:
HTTP_PROXY=http://127.0.0.1:7890
USER_AGENT=CodePapr/0.1.0
# Tool filtering
allowedTools: duckduckgo_web_search
# Name
Remote Knowledge Base
# Transport
streamable-http
# URL
url: https://example.com/mcp
# Headers (one Header-Name: value per line)
headers:
Authorization: Bearer your-token-here
X-API-Key: your-api-key
requireConfirmationrequireConfirmationControl the subset of tools exposed by each server via allowedTools and deniedTools:
* wildcards (e.g. describe*, list_*)allowedTools=query,describe*,list* + deniedTools=delete*,drop*,truncate*,update*,insert*, ensuring read-only access| Setting | Default | Description |
|---|---|---|
enabled | false | MCP master switch; all MCP servers are disabled when off |
exposeTools | true | Whether to expose MCP tools to the Agent; when off, MCP is only a background connection and does not appear in the tool list |
resultMaxBytes | 200,000 | Maximum bytes per tool call result (1KB – 5MB) |
ImmutablePrefix tool definition hash. Adding/removing/modifying MCP servers will break the prefix cache, requiring cache rebuild on the next request. It is recommended to finalize MCP configuration before starting a long session.
| Package | Role | Primary Responsibility |
|---|---|---|
@codepapr/types | Shared protocol layer | Unified message, request, response, tool, and statistics types |
@codepapr/common | Common infrastructure | Logging, hashing, and general utilities |
@codepapr/core | Runtime core | Agent, Session, ToolRegistry, cache partitioning, ProjectGraph, Prompt assembly |
@codepapr/api | Provider adapter layer | RequestBuilder, CacheValidator, provider implementations |
@codepapr/editor | Editor contract | Framework-agnostic Monaco types, markers, navigation, and static check contracts |
@codepapr/ui | Desktop workbench | React, Zustand, Tauri, WorkerBackedAgent; Tauri commands are thin JSON-RPC clients, while the host owns the main SQLite handles through codepapr-core::db |
The Tauri desktop is not a monolithic backend: src-tauri keeps GUI-only capabilities and thin RPC proxies. File system, Git, Shell, LSP, database, MCP, Web, and other domain implementations live in codepapr-core and are exposed uniformly by codepapr-server over JSON-RPC.
src-tauri/src/commands.rs: Tauri commands that proxy UI requests to host.rssrc-tauri/src/host.rs: starts/connects to codepapr-server, sends JSON-RPC, and forwards notifications to the Tauri event buscrates/codepapr-server: RPC routing, parameter validation, event broadcasting, and task queuecrates/codepapr-core: domain subsystems such as workspace_fs, git_operations, shell, lsp, db, mcp_host, and webThe desktop does not invoke the core Agent directly; instead, it offloads the LLM chat loop into a Web Worker via WorkerBackedAgent, ensuring long tasks do not block the UI.
WorkerCrashError, automatically clears the current agent instance (next send creates a new Worker), and prepends "Agent Worker crashed." to the error messageSTREAM_SNAPSHOT_INTERVAL_MS), onStreamSnapshot is triggered to persist in-flight content to the project SQLite| Layer | Technology |
|---|---|
| Frontend UI | React 18, TypeScript, Zustand 5, Monaco Editor, Tailwind CSS 3, Vite 8 |
| Desktop Framework | Tauri 2 (Rust) |
| Rust Host / Client | codepapr-server + codepapr-core (JSON-RPC, SQLite, tree-sitter, LSP, and other domain capabilities); thin Tauri client owns GUI-only capabilities |
| Agent Offload | Web Workers |
| Testing | Vitest 4, Playwright (UI E2E) |
The model does not get one blob. Full layering and memory flow: Context layering. Earlier bytes stay still so prefix cache works:
| Holds | Changes when | Cache | |
|---|---|---|---|
| 01 System core | System prompt, tools, params, AGENTS.md | Frozen for the session | Hit |
| 02 Session bootstrap | Skills catalog, memory section, long-term guidance | Next turn after MEMORY.md is saved | Usually a hit |
| 03 Session state | Checkpoint + retained recent turns | Rewritten on compaction | Hit within an epoch |
| 04 This turn | Current user message + tool results | Append-only | Tail increment |
Prefix cache hits automatically by byte-exact prefix match (no explicit breakpoints). The first principle is: keep the prefix byte-stable (append-only) within an epoch; reset it deliberately only across epochs via compaction.
Context grows with tool results during the tool loop. Agent.chat estimates the context size before building each round's request; when the effective threshold is exceeded, it compacts (resetting the log into a new epoch) and continues:
The old protection-window pruning layer was removed with v4: tool results now only exist inside the ≤5 most recent verbatim rounds — anything older is already folded by the skeleton, so separate pruning is meaningless. A single oversized tool output is bounded by the entry guardrails (tool-output truncation and artifact spillover, readable back via history_read_artifact). The trigger remains a single line: 90% of the context window.
maxContextTokens declares the model input window (default 200K) and applies uniformly to DeepSeek, OpenAI-compatible, and Claude providers (no per-provider clamping). The compaction trigger line = window × 90% (constant COMPACT_TRIGGER_RATIO) — the same source for the main session, mid-loop, Goal, and task sub-agents; provider-measured usage and the estimate take the larger value, and genuinely over-limit requests still fall back to emergency compaction. A higher window → fewer compactions → higher hit rate (cache reads are cheap).
sortedStringify (matching the live path); empty assistant content is ''reasoning_content is round-tripped based on "presence + model capability", decoupled from the per-request thinking toggleKnown limitations: LLM prefix cache has a lifetime; after a long idle period the first call re-misses the whole prefix (independent of the client). Compaction is lossy — the higher the threshold, the more history a single compaction covers.
The desktop LSP uses a Tauri native host + stdio JSON-RPC architecture, managing language server subprocesses, stdin writes, stdout reader threads, and message queues via src-tauri/src/lsp.rs.
| Language | Primary LSP Server | Type | Built-in |
|---|---|---|---|
| TypeScript / JS / TSX / JSX | typescript-language-server | Node.js npm | Yes |
| HTML | vscode-html-language-server | Node.js npm | Yes |
| CSS / SCSS / LESS | vscode-css-language-server | Node.js npm | Yes |
| JSON / JSONC | vscode-json-language-server | Node.js npm | Yes |
| YAML | yaml-language-server | Node.js npm | Yes |
| Python | pyright | Node.js npm | Yes |
| ShellScript | bash-language-server | Node.js npm | Yes |
| C# | csharp-ls / CodePapr.CSharp.Analyzer / omnisharp | .NET binary | Yes |
| Rust | rust-analyzer | Native binary | Yes |
| Java | Eclipse JDTLS + Temurin JRE 21 | Java binary | Yes |
| C / C++ | clangd v22.1.6 | Native binary | Yes |
| Go | gopls | Native binary | Yes (best effort) |
| Swift | sourcekit-lsp (macOS Xcode toolchain) | System | No |
| SQL | sqls | Native binary | Yes |
| Markdown | marksman | Native binary | Yes |
C# has a multi-layer fallback mechanism for LSP:
csharp-ls on system PATH or in ~/.dotnet/toolscsharp-ls binary (generated/lsp-tools/csharp-ls/bin/)CodePapr.CSharp.Analyzer (custom Roslyn sidecar, supports cross-file and cross-ProjectReference resolution)dotnet run --project CodePapr.CSharp.Analyzer.csproj (development / source code fallback)omnisharp -lsp or OmniSharp -lsp on system PATH (static candidate only)The desktop manages on-demand installation of missing LSP tools at runtime:
dotnet tool install -g csharp-ls, or uses the built-in Roslyn sidecarCODEPAPR_DISABLE_MANAGED_LSP_DOWNLOAD=1Built-in tree-sitter syntax tree parsing used for ProjectGraph and fallback symbol extraction: TypeScript, JavaScript, Python, Rust, Java, Go, C++, Bash, C#, CSS, HTML, JSON, PHP, Ruby, Kotlin, Swift.
| Command | Scope | Suitable Scenario |
|---|---|---|
npm run build | Full workspace build | After source changes, confirm artifacts can be generated |
npm run test | Full workspace tests | Daily main regression |
npm run test:e2e:ui | Playwright UI E2E | Changes to desktop UI components, Toast, permissions, Code Review |
npm run test:e2e:ui:install | Install Playwright Chromium | Preparation before first UI E2E run |
npm run lint | Static analysis | Pre-commit quality gate |
npm run audit | Security audit | Before release or after dependency changes |
npm run smoke:agent-tools | Real model tool smoke test | Changes to tool selection, shell, browser interaction |
npm run smoke:lsp-preview | Multi-language LSP smoke test | Changes to LSP hover, definition |
npm run verify | Most comprehensive verification | Before local release (includes cargo check) |
npm run build
npm run test
npm run test:e2e
npm run test:e2e:ui
npm run verify
Browser dependencies must be installed before the first UI E2E run:
npm run test:e2e:ui:install
# Development debugging
npm run debug
# Optimized desktop runtime (no packaging)
npm run release
# Generate installer (.dmg / .msi) and organize into Release/
npm run publish
./publish-codepapr.commandpublish-codepapr.cmdnpm run release:prep
npm run publish:dry-run
Best when working with a repository for the first time or when requirements are unclear:
Best when you already know the target but don't want to manually search and fix:
Fix the incorrect cache statistics in packages/@codepapr/api.
First locate the statistics aggregation logic, then make a minimal fix, and finally run related tests.
Best for UI adjustments, page behavior verification, and preview integration:
Best for scripts, REPL, interactive CLI, or multi-step shell workflows:
| Model | Context | Max Output | Cache Hit Input | Cache Miss Input | Output | Concurrency |
|---|---|---|---|---|---|---|
deepseek-flash | 1M | 384K | 0.02 CNY/M tokens | 1 CNY/M tokens | 2 CNY/M tokens | 2500 |
deepseek-v4-pro | 1M | 384K | 0.025 CNY/M tokens | 3 CNY/M tokens | 6 CNY/M tokens | 500 |
deepseek-v4-pro — used for Ask, Plan, Agent, and App main execution flow; App mode always uses the primary model for generation qualitydeepseek-flash — used for context compression, sub-task planning, read-only lightweight sub-agentsmax (strongest reasoning); can be switched to high in the LLM settings tabFirst check whether the desktop settings have been saved, and whether the corresponding environment variables are set (DEEPSEEK_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY).
Confirm whether npm install and npm run build have been executed, and whether the current repository is under a OneDrive path causing .bin shim anomalies.
First suspect uninstalled dependencies or unbuilt local packages, rather than cloud sync or disk issues.
Usually because no detectable Chrome or Chromium-compatible browser is installed on the machine.
Many packages in this repository participate in tests or references through their respective dist entry points. After changing source files, if results look unchanged, first rebuild the affected packages, then run verification.
Important: Modify source → build first → run affected tests → run broader verification. When results appear "not taking effect," first suspect the build wasn't applied, rather than suspecting a runtime anomaly.
In settings, you can connect to a local model provider (OpenAI-compatible endpoint) for offline or private deployment scenarios. With supported models, you can paste or drag images directly into the chat box as input.
This is the desktop's external path permission mechanism. When the Agent attempts to read or list absolute paths outside the project, it requests your explicit authorization to ensure system files are not accessed without permission.
First confirm whether Playwright browser dependencies have been installed:
npm run test:e2e:ui:install
UI E2E uses Chromium running in a mock environment without Tauri webview; real model configuration is not required.
Beginners: First use Ask to understand the system → then Plan to see the scope of changes clearly → finally use Agent for actual execution. Need data visualization? Switch to App mode and generate interactive charts in one sentence.
Experienced users: Give clear goals directly in Agent mode → specify affected files and verification requirements → use the desktop to complete conversation, Git, preview, and browser integration.
CodePapr v0.1.0 · This tutorial is based on the project source code and documentation · Content is continuously updated