Release 0.1.0: MIT license, changelog, multi-arch Docker image without CLI builds
- LICENSE (MIT), CHANGELOG for 0.1.0, README overhaul - docker-compose.release.yml pulling the registry image - Dockerfile cross-compiles the server with cargo-zigbuild for amd64 and arm64; the terminal client is no longer built into the image - Server, install script and settings point to a source install of the terminal client when no prebuilt binaries are available (/info: cli_builds) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d14c609576
commit
ed9942829a
15 files changed
+381
-106
No files matched your search
@@ -26,3 +26,9 @@ OPENROUTER_API_KEY=
|
|||||||
|
|
||||||
# Time zone for automations (cron schedules) and timestamps, e.g. Europe/Berlin
|
# Time zone for automations (cron schedules) and timestamps, e.g. Europe/Berlin
|
||||||
TZ=UTC
|
TZ=UTC
|
||||||
|
|
||||||
|
# Image version for docker-compose.release.yml (e.g. 0.1.0); default: latest
|
||||||
|
CODECRAFT_VERSION=latest
|
||||||
|
|
||||||
|
# Log format: empty for text, "json" for one JSON object per line
|
||||||
|
CODECRAFT_LOG_FORMAT=
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
|
||||||
|
until 1.0, minor versions may contain breaking changes.
|
||||||
|
|
||||||
|
## [0.1.0] – 2026-11-09
|
||||||
|
|
||||||
|
First public release.
|
||||||
|
|
||||||
|
### Agents and chat
|
||||||
|
|
||||||
|
- Agent loop with streaming, task lists, subagents (parallel and in the background, on other
|
||||||
|
models), skills, slash commands, `AGENTS.md` / `CLAUDE.md`, automatic context compaction.
|
||||||
|
- Modes: **build**, **plan** (read-only) and **craft** (study a website, app, game or old
|
||||||
|
program and build your own version, with visual comparison, clean room or deep mode),
|
||||||
|
plus custom modes and subagents. Review loops per mode.
|
||||||
|
- Tools: files, shell with background processes, web fetch and search, LSP diagnostics after
|
||||||
|
edits, OpenSCAD for 3D printing, Ghidra for old binaries, image generation (fal.ai), and an
|
||||||
|
interactive **browser** (click, type, run JavaScript, screenshots, console errors; private
|
||||||
|
network addresses are blocked).
|
||||||
|
- MCP servers (stdio and Streamable HTTP, elicitation, tools loaded on demand).
|
||||||
|
- Permissions per tool and per shell command pattern, modes *ask*, *auto*, *accept edits* and
|
||||||
|
*bypass*; permission cards with diffs; questions from agents and MCP servers.
|
||||||
|
- Checkpoints and rewind, fork, regenerate, accept changes hunk by hunk, git worktrees per
|
||||||
|
session, reasoning effort per message, voice input, `@file` mentions, attachments.
|
||||||
|
- Project memory (`.codecraft/memory.md`, written by the agent) and personal memory.
|
||||||
|
- Hooks before and after tool calls, on prompts and at the end of a turn.
|
||||||
|
|
||||||
|
### Models
|
||||||
|
|
||||||
|
- Anthropic natively and every OpenAI-compatible API (Gemini, OpenRouter, opencode,
|
||||||
|
fal.ai, Ollama, vLLM, llama.cpp, LM Studio).
|
||||||
|
- Prices per model, concurrency limits per host and model, monthly budgets.
|
||||||
|
- **Model fallback** when a host is unreachable or a budget is used up.
|
||||||
|
- **Provider status**: every 5 minutes each provider's model list is checked (no tokens).
|
||||||
|
|
||||||
|
### Web app
|
||||||
|
|
||||||
|
- Installable PWA with push notifications (permissions, questions, finished turns) and a
|
||||||
|
**share target**: text and links shared from other apps start a chat or go into a recent one.
|
||||||
|
- Guided start screen, file manager with previews (PDF, Office, 3D models, images), web
|
||||||
|
terminal, image gallery, git panel.
|
||||||
|
- **Command palette** (Ctrl/Cmd+K) and keyboard shortcuts; **prompt templates** with
|
||||||
|
placeholders (personal and global); sessions can be **pinned, archived and filed into
|
||||||
|
folders**, grouped by date or project.
|
||||||
|
- Statistics: tokens, cache hits, time to first token, prefill and output speed and cost per
|
||||||
|
request; cost and tokens per day, an activity heatmap of the last 14 days, tables per model,
|
||||||
|
provider, mode, user and session. Optional **daily cost summary** as a push at 20:00.
|
||||||
|
- 15 colour themes, each light and dark; English and German.
|
||||||
|
- "What's new" after updates; admins see when a new release is available.
|
||||||
|
|
||||||
|
### Automations and integrations
|
||||||
|
|
||||||
|
- **Automations**: agents on a cron schedule from a Markdown job file, created by an agent,
|
||||||
|
from a **template** or by hand; **incoming webhooks** start them (shared secret or
|
||||||
|
Gitea/GitHub HMAC signature; the payload is passed to the agent).
|
||||||
|
- **API tokens** with full or read-only scope.
|
||||||
|
- **Prometheus metrics** at `/metrics` (own bearer token) and JSON logs
|
||||||
|
(`CODECRAFT_LOG_FORMAT=json`).
|
||||||
|
- **Backups**: daily zip of database and config, keep 30, optional copy to any S3-compatible
|
||||||
|
bucket; download from the settings.
|
||||||
|
|
||||||
|
### Terminal client
|
||||||
|
|
||||||
|
- `codecraft`: a full-screen terminal client like Claude Code or opencode. The agent loop,
|
||||||
|
tools and history stay on your machine; models, modes, rules, skills and the theme come
|
||||||
|
from the server, which counts usage and costs. Also runs **without a server**: a guided
|
||||||
|
setup connects Anthropic, OpenAI, Gemini, OpenRouter, opencode or local servers (Ollama,
|
||||||
|
LM Studio, llama.cpp/vLLM, detected automatically).
|
||||||
|
- No prebuilt binaries in this release: install it from source with
|
||||||
|
`cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli`.
|
||||||
|
|
||||||
|
### Users and security
|
||||||
|
|
||||||
|
- Local accounts (Argon2) and single sign-on via OpenID Connect; admins and users, private
|
||||||
|
folders per user, shared folders, read-only session sharing, audit log.
|
||||||
|
- Shell commands of non-admin users run in a bubblewrap sandbox.
|
||||||
|
- Multi-arch Docker image (amd64, arm64).
|
||||||
|
|
||||||
|
[0.1.0]: https://git.familie-zink.org/zink/codecraft/releases/tag/v0.1.0
|
||||||
+27
-26
@@ -1,16 +1,35 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# Multi-arch: the web UI and the server are built once on the build
|
||||||
|
# machine (cross-compiled with cargo-zigbuild); only the runtime stage runs
|
||||||
|
# per target platform.
|
||||||
|
|
||||||
# --- web UI (PWA) -------------------------------------------------------------
|
# --- web UI (PWA) -------------------------------------------------------------
|
||||||
FROM node:22-alpine AS web
|
FROM --platform=$BUILDPLATFORM node:22-alpine AS web
|
||||||
WORKDIR /web
|
WORKDIR /web
|
||||||
COPY web/package.json web/package-lock.json ./
|
COPY web/package.json web/package-lock.json ./
|
||||||
RUN npm ci --no-audit --no-fund
|
RUN npm ci --no-audit --no-fund
|
||||||
COPY web/ ./
|
COPY web/ ./
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# --- server -------------------------------------------------------------------
|
# --- Rust toolchain with zig for cross-compiling --------------------------------
|
||||||
FROM rust:1-bookworm AS server
|
FROM --platform=$BUILDPLATFORM rust:1-bookworm AS toolchain
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends cmake xz-utils && rm -rf /var/lib/apt/lists/*
|
||||||
|
ARG ZIG_VERSION=0.17.1
|
||||||
|
RUN curl -fsSL https://ziglang.org/download/${ZIG_VERSION}/zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz | tar -xJ -C /opt \
|
||||||
|
&& ln -s /opt/zig-*/zig /usr/local/bin/zig \
|
||||||
|
&& cargo install --locked cargo-zigbuild \
|
||||||
|
&& rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
|
# --- server (for the target platform, glibc of Debian bookworm) ----------------
|
||||||
|
FROM toolchain AS server
|
||||||
|
ARG TARGETARCH
|
||||||
|
RUN case "$TARGETARCH" in \
|
||||||
|
amd64) echo x86_64-unknown-linux-gnu ;; \
|
||||||
|
arm64) echo aarch64-unknown-linux-gnu ;; \
|
||||||
|
*) echo "unsupported architecture $TARGETARCH" >&2; exit 1 ;; \
|
||||||
|
esac > /target
|
||||||
COPY config.example.toml ./
|
COPY config.example.toml ./
|
||||||
COPY Cargo.toml Cargo.lock ./
|
COPY Cargo.toml Cargo.lock ./
|
||||||
COPY core/Cargo.toml ./core/
|
COPY core/Cargo.toml ./core/
|
||||||
@@ -19,33 +38,16 @@ COPY cli/Cargo.toml ./cli/
|
|||||||
# Cache dependencies separately from the sources (stub crates first).
|
# Cache dependencies separately from the sources (stub crates first).
|
||||||
RUN mkdir -p core/src server/src cli/src \
|
RUN mkdir -p core/src server/src cli/src \
|
||||||
&& echo '' > core/src/lib.rs && echo 'fn main(){}' > server/src/main.rs && echo 'fn main(){}' > cli/src/main.rs \
|
&& echo '' > core/src/lib.rs && echo 'fn main(){}' > server/src/main.rs && echo 'fn main(){}' > cli/src/main.rs \
|
||||||
&& cargo build --release -p codecraft && rm -rf core/src server/src cli/src
|
&& cargo zigbuild --release -p codecraft --target "$(cat /target).2.36" && rm -rf core/src server/src cli/src
|
||||||
COPY core/src ./core/src
|
COPY core/src ./core/src
|
||||||
COPY server/src ./server/src
|
COPY server/src ./server/src
|
||||||
COPY server/resources-cli ./server/resources-cli
|
COPY server/resources-cli ./server/resources-cli
|
||||||
COPY cli/src ./cli/src
|
COPY cli/src ./cli/src
|
||||||
ARG GIT_COMMIT=""
|
ARG GIT_COMMIT=""
|
||||||
ENV CODECRAFT_COMMIT=${GIT_COMMIT}
|
ENV CODECRAFT_COMMIT=${GIT_COMMIT}
|
||||||
RUN touch core/src/lib.rs server/src/main.rs && cargo build --release -p codecraft
|
RUN touch core/src/lib.rs server/src/main.rs \
|
||||||
|
&& cargo zigbuild --release -p codecraft --target "$(cat /target).2.36" \
|
||||||
# --- terminal client (static Linux binaries for x86_64 and aarch64) -----------
|
&& cp "target/$(cat /target)/release/codecraft" /codecraft
|
||||||
FROM rust:1-bookworm AS cli
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends cmake xz-utils && rm -rf /var/lib/apt/lists/*
|
|
||||||
ARG ZIG_VERSION=0.17.1
|
|
||||||
RUN curl -fsSL https://ziglang.org/download/${ZIG_VERSION}/zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz | tar -xJ -C /opt \
|
|
||||||
&& ln -s /opt/zig-*/zig /usr/local/bin/zig \
|
|
||||||
&& cargo install --locked cargo-zigbuild \
|
|
||||||
&& rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
|
|
||||||
WORKDIR /src
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
|
||||||
COPY core ./core
|
|
||||||
COPY server/Cargo.toml ./server/
|
|
||||||
COPY server/resources ./server/resources
|
|
||||||
COPY cli ./cli
|
|
||||||
RUN mkdir -p server/src && echo 'fn main(){}' > server/src/main.rs \
|
|
||||||
&& cargo zigbuild --release -p codecraft-cli --target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl \
|
|
||||||
&& mkdir -p /out && cp target/x86_64-unknown-linux-musl/release/codecraft /out/codecraft-linux-x86_64 \
|
|
||||||
&& cp target/aarch64-unknown-linux-musl/release/codecraft /out/codecraft-linux-aarch64
|
|
||||||
|
|
||||||
# --- runtime ------------------------------------------------------------------
|
# --- runtime ------------------------------------------------------------------
|
||||||
# Node is included so agents can work on JS projects and run npx-based MCP servers.
|
# Node is included so agents can work on JS projects and run npx-based MCP servers.
|
||||||
@@ -62,9 +64,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
# Language servers for diagnostics after edits (rust-analyzer/gopls/clangd can be
|
# Language servers for diagnostics after edits (rust-analyzer/gopls/clangd can be
|
||||||
# installed by agents: rustup component add rust-analyzer, go install …).
|
# installed by agents: rustup component add rust-analyzer, go install …).
|
||||||
RUN npm install -g typescript@5 typescript-language-server pyright && npm cache clean --force
|
RUN npm install -g typescript@5 typescript-language-server pyright && npm cache clean --force
|
||||||
COPY --from=server /src/target/release/codecraft /usr/local/bin/codecraft
|
COPY --from=server /codecraft /usr/local/bin/codecraft
|
||||||
COPY --from=web /web/dist /app/web
|
COPY --from=web /web/dist /app/web
|
||||||
COPY --from=cli /out /app/cli
|
|
||||||
COPY server/ghidra /app/ghidra
|
COPY server/ghidra /app/ghidra
|
||||||
COPY server/resources /app/resources
|
COPY server/resources /app/resources
|
||||||
# The agent's home lives on the data volume: tools it installs in user space
|
# The agent's home lives on the data volume: tools it installs in user space
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Richard Zink
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -5,35 +5,38 @@
|
|||||||
<h1 align="center">CodeCraft</h1>
|
<h1 align="center">CodeCraft</h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<b>A self-hosted coding agent for your browser: any model, your tools, your rules.</b><br>
|
<b>A self-hosted coding agent for your browser and terminal: any model, your tools, your rules.</b><br>
|
||||||
Run Claude, Gemini, opencode Go, fal.ai or your own models as coding agents with files, shell, MCP and subagents,<br>
|
Run Claude, Gemini, OpenRouter, opencode or your own models as coding agents with files, shell, MCP and subagents,<br>
|
||||||
approve what they do from any device, and see exactly what every request costs.
|
approve what they do from any device, automate recurring work, and see exactly what every request costs.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
|
<img alt="Version 0.1.0" src="https://img.shields.io/badge/version-0.1.0-d69e2e?style=flat-square">
|
||||||
|
<img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-689d6a?style=flat-square">
|
||||||
<img alt="Rust backend" src="https://img.shields.io/badge/backend-Rust-b7410e?style=flat-square&logo=rust">
|
<img alt="Rust backend" src="https://img.shields.io/badge/backend-Rust-b7410e?style=flat-square&logo=rust">
|
||||||
<img alt="React PWA" src="https://img.shields.io/badge/frontend-React%20PWA-2d81ff?style=flat-square&logo=react">
|
<img alt="React PWA" src="https://img.shields.io/badge/frontend-React%20PWA-2d81ff?style=flat-square&logo=react">
|
||||||
<img alt="Docker" src="https://img.shields.io/badge/deploy-Docker-1d63ed?style=flat-square&logo=docker&logoColor=white">
|
<img alt="Docker: amd64 and arm64" src="https://img.shields.io/badge/docker-amd64%20%7C%20arm64-1d63ed?style=flat-square&logo=docker&logoColor=white">
|
||||||
<img alt="Status: early alpha" src="https://img.shields.io/badge/status-early%20alpha-d69e2e?style=flat-square">
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
|
<a href="#install">Install</a> ·
|
||||||
<a href="#how-it-works">How it works</a> ·
|
<a href="#how-it-works">How it works</a> ·
|
||||||
<a href="#modes">Modes</a> ·
|
<a href="#modes">Modes</a> ·
|
||||||
<a href="#models">Models</a> ·
|
<a href="#models">Models</a> ·
|
||||||
<a href="#users">Users</a> ·
|
<a href="#terminal-client">Terminal client</a> ·
|
||||||
|
<a href="#automations">Automations</a> ·
|
||||||
|
<a href="#integrations">Integrations</a> ·
|
||||||
|
<a href="#users-and-security">Users</a> ·
|
||||||
<a href="#statistics">Statistics</a> ·
|
<a href="#statistics">Statistics</a> ·
|
||||||
<a href="#get-started">Get started</a> ·
|
|
||||||
<a href="#configuration">Configuration</a> ·
|
<a href="#configuration">Configuration</a> ·
|
||||||
<a href="#themes">Themes</a> ·
|
<a href="#themes">Themes</a> ·
|
||||||
<a href="#development">Development</a> ·
|
<a href="#development">Development</a>
|
||||||
<a href="#status">Status</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="docs/images/chat.png" alt="A CodeCraft session: the agent edits a file, a permission card shows the diff and asks before running a command, the task list shows what is left" width="100%">
|
<img src="docs/images/chat.png" alt="A CodeCraft session: the agent edits a file, a permission card shows the command and asks before running it, the task list shows what is left" width="100%">
|
||||||
<br>
|
<br>
|
||||||
<sub>A session: the agent works through its task list, shows diffs, and asks before anything outside the rules.</sub>
|
<sub>A session: the agent works through its task list, shows diffs, and asks before anything outside the rules.</sub>
|
||||||
</p>
|
</p>
|
||||||
@@ -41,47 +44,84 @@
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="25%" valign="top">
|
<td width="25%" valign="top">
|
||||||
<h3>🧠 Any model</h3>
|
<h3>Any model</h3>
|
||||||
Anthropic natively, plus everything that speaks the OpenAI API: Gemini, opencode Go, fal.ai, OpenRouter, Ollama, vLLM, llama.cpp. Mix them in one chat.
|
Anthropic natively, plus everything that speaks the OpenAI API: Gemini, OpenRouter, opencode, fal.ai, Ollama, vLLM, llama.cpp. Mix them in one chat, with automatic fallback.
|
||||||
</td>
|
</td>
|
||||||
<td width="25%" valign="top">
|
<td width="25%" valign="top">
|
||||||
<h3>🛠️ Real tools</h3>
|
<h3>Real tools</h3>
|
||||||
Read, write, edit, glob, grep, shell, web fetch, task lists, subagents, skills – and every tool of your MCP servers.
|
Files, shell, web, an interactive browser, LSP diagnostics, task lists, subagents, skills – and every tool of your MCP servers.
|
||||||
</td>
|
</td>
|
||||||
<td width="25%" valign="top">
|
<td width="25%" valign="top">
|
||||||
<h3>🙋 You decide</h3>
|
<h3>You decide</h3>
|
||||||
Permission requests with diffs, questions from agents and MCP servers, per-tool rules. On your phone, with notifications.
|
Permission cards with diffs, questions from agents and MCP servers, per-tool rules. On your phone, with push notifications.
|
||||||
</td>
|
</td>
|
||||||
<td width="25%" valign="top">
|
<td width="25%" valign="top">
|
||||||
<h3>📊 Every token counted</h3>
|
<h3>Every token counted</h3>
|
||||||
Tokens, cache hits, prefill and output speed, and cost per request – per chat and in a dashboard.
|
Tokens, cache hits, prefill and output speed, and cost per request – per chat, per day and per model.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
You need Docker with Compose. The image is published for **amd64 and arm64**.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir codecraft && cd codecraft
|
||||||
|
curl -fsSLO https://git.familie-zink.org/zink/codecraft/raw/branch/main/docker-compose.release.yml
|
||||||
|
curl -fsSL --create-dirs -o docker/seccomp-sandbox.json \
|
||||||
|
https://git.familie-zink.org/zink/codecraft/raw/branch/main/docker/seccomp-sandbox.json
|
||||||
|
curl -fsSL -o .env https://git.familie-zink.org/zink/codecraft/raw/branch/main/.env.example
|
||||||
|
$EDITOR .env # workspace path, provider keys, time zone
|
||||||
|
docker compose -f docker-compose.release.yml up -d
|
||||||
|
docker compose -f docker-compose.release.yml logs codecraft # one-time setup code for the first admin
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `http://localhost:8787`, enter the setup code and create the admin account. Then add a
|
||||||
|
provider under *Settings → Providers & models* – or put the keys into `.env` and reference
|
||||||
|
them in the config as `${NAME}`.
|
||||||
|
|
||||||
|
**Update:** `docker compose -f docker-compose.release.yml pull && docker compose -f docker-compose.release.yml up -d`.
|
||||||
|
Pin a version with `CODECRAFT_VERSION=0.1.0` in `.env`. Admins see a notice when a new release is out.
|
||||||
|
|
||||||
|
**From source:** `git clone https://git.familie-zink.org/zink/codecraft.git && cd codecraft`,
|
||||||
|
`cp .env.example .env`, then `docker compose up -d --build`.
|
||||||
|
|
||||||
|
All state – configuration, database, backups, the agent's home directory – lives in the Docker
|
||||||
|
volume `codecraft-data`; recreating the container keeps it. Your projects are mounted from
|
||||||
|
`WORKSPACE`. The port is bound to `127.0.0.1`: put a TLS reverse proxy in front of it (with
|
||||||
|
WebSocket support) and set `auth.public_url` – installing the app and push notifications
|
||||||
|
require HTTPS.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
CodeCraft runs on your server, next to your projects. You talk to it from a browser or the
|
CodeCraft runs on your server, next to your projects. You talk to it from a browser, the
|
||||||
installed app; the agent keeps working when you close the tab.
|
installed app or the terminal client; the agent keeps working when you close the tab.
|
||||||
|
|
||||||
1. **Pick a folder and a mode.** Every user has their own folder; admins can share more.
|
1. **Pick a folder and a task.** The start screen asks what you want to do – build, plan,
|
||||||
|
craft something, model a part for 3D printing – and where: a new folder, an existing one
|
||||||
|
or a git repository.
|
||||||
2. **Say what you want.** The agent plans with a task list, reads the code and makes changes.
|
2. **Say what you want.** The agent plans with a task list, reads the code and makes changes.
|
||||||
3. **Approve or answer.** Anything outside your rules shows up as a card: allow once, allow
|
3. **Approve or answer.** Anything outside your rules shows up as a card: allow once, allow
|
||||||
for the session, or reject with feedback. Questions from agents and MCP servers too.
|
for the session, or reject with feedback. Questions from agents and MCP servers too.
|
||||||
4. **Delegate.** The agent hands work to subagents – in parallel or in the background, on
|
4. **Delegate.** The agent hands work to subagents – in parallel or in the background, on
|
||||||
other models and hosts – and continues while they run.
|
other models and hosts – and continues while they run.
|
||||||
|
|
||||||
|
Every change can be reviewed hunk by hunk, rewound to a checkpoint, or isolated in a git
|
||||||
|
worktree. Sessions can be pinned, archived and filed into folders; <kbd>Ctrl</kbd>+<kbd>K</kbd>
|
||||||
|
opens the command palette, and prompt templates with placeholders save typing.
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" valign="top">
|
<td width="40%" valign="top">
|
||||||
<img src="docs/images/mobile.png" alt="CodeCraft on a phone: a session with a question card offering three options" width="100%"><br>
|
<img src="docs/images/mobile.png" alt="CodeCraft on a phone: a session with a question card offering three options" width="100%"><br>
|
||||||
<sub><b>Mobile:</b> answer questions and approve changes from your phone.</sub>
|
<sub><b>Mobile:</b> answer questions and approve changes from your phone. Share links and text from other apps into a chat.</sub>
|
||||||
</td>
|
</td>
|
||||||
<td width="50%" valign="top">
|
<td width="60%" valign="top">
|
||||||
<img src="docs/images/settings.png" alt="Settings: providers with models, context sizes and prices per million tokens" width="100%"><br>
|
<img src="docs/images/settings.png" alt="Settings: providers with model counts and their status (reachable, API key rejected)" width="100%"><br>
|
||||||
<sub><b>Settings:</b> providers, models, prices, MCP, permissions and users – all in the UI.</sub>
|
<sub><b>Settings:</b> providers, models, prices, MCP, permissions, users, templates and backups – all in the UI.</sub>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -92,11 +132,13 @@ installed app; the agent keeps working when you close the tab.
|
|||||||
|---|---|
|
|---|---|
|
||||||
| **build** | Full access: implement, edit, run. |
|
| **build** | Full access: implement, edit, run. |
|
||||||
| **plan** | Read-only: investigate, ask, and propose a step-by-step plan. One click switches to build. |
|
| **plan** | Read-only: investigate, ask, and propose a step-by-step plan. One click switches to build. |
|
||||||
| **craft** | Study a target, build your own version, check it visually, refine. Websites are captured at several screen widths in a headless browser and compared with the build (similarity per page and width). *Clean room* uses only what a visitor sees; *deep mode* may read the page source. |
|
| **craft** | Study a target – a website, app, game or old program – and build your own version, check it visually and refine. Websites are captured at several screen widths in a headless browser and compared with the build. *Clean room* uses only what a visitor sees; *deep mode* may read the source. |
|
||||||
| *custom* | Your own modes and subagents – in the UI, the config file or as Markdown in `.codecraft/agents` / `.claude/agents`. |
|
| *custom* | Your own modes and subagents – in the UI, the config file or as Markdown in `.codecraft/agents` / `.claude/agents`. |
|
||||||
|
|
||||||
Projects keep working the way they do in Claude Code and opencode: `AGENTS.md`, `CLAUDE.md`,
|
Projects keep working the way they do in Claude Code and opencode: `AGENTS.md`, `CLAUDE.md`,
|
||||||
slash commands in `.claude/commands` and skills in `.claude/skills` are picked up automatically.
|
slash commands in `.claude/commands` and skills in `.claude/skills` are picked up automatically.
|
||||||
|
The agent keeps notes about a project in `.codecraft/memory.md`; your personal memory applies to
|
||||||
|
every project.
|
||||||
|
|
||||||
## Models
|
## Models
|
||||||
|
|
||||||
@@ -105,76 +147,108 @@ output limit, reasoning effort, extra request options and prices per million tok
|
|||||||
|
|
||||||
- **Several models per chat:** switch the model at any time, give modes a fixed model, and
|
- **Several models per chat:** switch the model at any time, give modes a fixed model, and
|
||||||
run subagents on other models – e.g. a coding model on one GPU host and a small model that
|
run subagents on other models – e.g. a coding model on one GPU host and a small model that
|
||||||
writes documentation and translations in the background on another.
|
writes documentation in the background on another.
|
||||||
|
- **Fallback:** if a host is unreachable or its budget is used up, the request goes to the
|
||||||
|
model's fallback.
|
||||||
- **Concurrency limits:** `max_concurrency` per host or model queues requests for servers that
|
- **Concurrency limits:** `max_concurrency` per host or model queues requests for servers that
|
||||||
can only process one at a time; `max_parallel` limits instances of a subagent. Waiting time
|
process one at a time; waiting time is shown and never counted as model latency.
|
||||||
is shown in the chat and never counted as model latency.
|
- **Status:** every five minutes each provider's model list is fetched (no tokens used), so
|
||||||
- **Background subagents:** the agent starts them with `background = true`, keeps working,
|
you see at a glance which hosts answer and which keys are rejected.
|
||||||
and receives their result as a message when they finish.
|
|
||||||
|
|
||||||
## Users
|
## Terminal client
|
||||||
|
|
||||||
|
`codecraft` is a full-screen terminal client in the style of Claude Code and opencode. The agent
|
||||||
|
loop, the tools and the chat history run **on your machine**, in the current folder. Signed in to
|
||||||
|
a CodeCraft server, it uses the server's models, keys, budgets, modes, rules, skills, MCP tools and
|
||||||
|
your theme, and the server counts usage and costs. Without a server, a guided setup connects
|
||||||
|
Anthropic, OpenAI, Gemini, OpenRouter, opencode or a local model server (Ollama, LM Studio,
|
||||||
|
llama.cpp, vLLM – detected automatically); both can be mixed.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli
|
||||||
|
codecraft login # server URL, user name, password → creates an API token
|
||||||
|
codecraft # start in the current folder; /help lists the commands
|
||||||
|
```
|
||||||
|
|
||||||
|
There are no prebuilt binaries yet, so the client is installed from source (needs a Rust
|
||||||
|
toolchain). A server that has binaries in `CODECRAFT_CLI_DIR` (`codecraft-linux-x86_64`,
|
||||||
|
`codecraft-linux-aarch64`) also offers `curl -fsSL https://<your-server>/cli/install.sh | sh`
|
||||||
|
and `codecraft update`.
|
||||||
|
|
||||||
|
## Automations
|
||||||
|
|
||||||
|
An automation is a Markdown file with a cron schedule in its front matter
|
||||||
|
(`.codecraft/jobs/<name>.md`). Each run is a normal chat session, so you can read and continue
|
||||||
|
it; if it needs a permission, you get a push notification. Ask an agent in any chat to set one
|
||||||
|
up, start from a template (dependency check, security review of recent commits, test suite
|
||||||
|
health, daily summary, TODO report, documentation freshness) or write the file yourself.
|
||||||
|
|
||||||
|
**Webhooks** start an automation from outside, e.g. on every push: the request is checked with a
|
||||||
|
shared secret or a Gitea/GitHub HMAC signature, and its JSON payload is handed to the agent.
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
|
||||||
|
- **API tokens** (*Settings → Account*) with full or read-only scope for scripts and the terminal client.
|
||||||
|
- **Prometheus:** set `server.metrics_token` and scrape `GET /metrics` with
|
||||||
|
`Authorization: Bearer <token>` – requests, errors, tokens, cost and time per model, provider
|
||||||
|
status, sessions, pending permissions.
|
||||||
|
- **JSON logs:** `CODECRAFT_LOG_FORMAT=json` writes one JSON object per line.
|
||||||
|
- **Backups:** daily at 03:00 into `/data/backups` (the last 30 are kept), optionally copied to
|
||||||
|
any S3-compatible bucket (AWS, MinIO, Garage, Backblaze B2, Hetzner). *Settings → Audit*
|
||||||
|
shows them, creates one on demand and downloads them.
|
||||||
|
- **Health:** `GET /api/health` for monitoring, with version and commit.
|
||||||
|
|
||||||
|
## Users and security
|
||||||
|
|
||||||
- Local accounts (Argon2 passwords) and single sign-on via OpenID Connect (Authentik, Authelia,
|
- Local accounts (Argon2 passwords) and single sign-on via OpenID Connect (Authentik, Authelia,
|
||||||
Keycloak, …) with optional admin and access groups.
|
Keycloak, …) with optional admin and access groups.
|
||||||
- **Admins** manage providers, MCP, permissions, users and shared folders and see all statistics.
|
- **Admins** manage providers, MCP, permissions, users and shared folders and see all statistics.
|
||||||
**Users** see their own sessions and statistics.
|
**Users** see their own sessions and statistics.
|
||||||
- Every user works in `<workspace>/<username>`; admins can share additional folders with
|
- Every user works in `<workspace>/<username>`; admins can share additional folders. Sessions
|
||||||
selected users. Sessions are private and can be shared read-only.
|
are private and can be shared read-only. An audit log records sign-ins, permissions and
|
||||||
|
configuration changes.
|
||||||
> [!NOTE]
|
- Shell commands of non-admin users run in a **bubblewrap sandbox**: read-only system, only
|
||||||
> File tools are confined to a user's folders. Shell commands run in the shared container and
|
their folders writable, own home and processes, no server environment. It needs the security
|
||||||
> are **not** sandboxed per user – only give accounts to people you trust with that container.
|
options in the compose file; without them non-admins cannot run shell commands.
|
||||||
|
- The browser tool reaches the internet and `localhost`, never addresses in private networks.
|
||||||
|
|
||||||
## Statistics
|
## Statistics
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="docs/images/stats.png" alt="The statistics dashboard: cost and token tiles, cost per day stacked by model, tokens per day, and an activity heatmap by weekday and hour" width="100%">
|
<img src="docs/images/stats.png" alt="The statistics dashboard: cost and token tiles, cost per day stacked by model, tokens per day, and an activity heatmap of the last 14 days" width="100%">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Every model request is stored with input, output and cache tokens, time to first token,
|
Every model request is stored with input, output and cache tokens, time to first token,
|
||||||
prefill and output speed, and its cost at the price configured at that moment. The dashboard
|
prefill and output speed, and its cost at the price configured at that moment. The dashboard
|
||||||
shows totals, cost per day by model, tokens per day, a weekday × hour heatmap, and tables per
|
shows totals, cost per day by model, tokens per day, an activity heatmap of the last 14 days,
|
||||||
model, provider, mode, user and session – each chart also as a table.
|
and tables per model, provider, mode, user and session – each chart also as a table. Turn on
|
||||||
|
the daily cost summary to get a push notification every evening.
|
||||||
## Get started
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git clone <this repository> codecraft && cd codecraft
|
|
||||||
cp .env.example .env # workspace path, provider keys, optional first admin
|
|
||||||
docker compose up -d --build
|
|
||||||
docker compose logs codecraft # shows the one-time setup code for the first admin
|
|
||||||
```
|
|
||||||
|
|
||||||
All state – configuration, database, the agent's home directory – lives in the Docker volume
|
|
||||||
`codecraft-data`; rebuilding or recreating the container keeps it. Your projects are mounted
|
|
||||||
from `WORKSPACE`.
|
|
||||||
|
|
||||||
The port is bound to `127.0.0.1` by default. Put a TLS reverse proxy in front of it (enable
|
|
||||||
WebSocket support) and set `auth.public_url` – installing the PWA requires HTTPS.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
One commented TOML file, `/data/config.toml` in the volume, created from
|
One commented TOML file, `/data/config.toml` in the volume, created from
|
||||||
[`config.example.toml`](config.example.toml) on first start. The settings page edits it in
|
[`config.example.toml`](config.example.toml) on first start. The settings pages edit it in
|
||||||
place and keeps your comments. Secrets belong in the environment and are referenced as
|
place and keep your comments. Secrets belong in the environment and are referenced as
|
||||||
`${NAME}`.
|
`${NAME}`.
|
||||||
|
|
||||||
| Section | Purpose |
|
| Section | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `[server]` | workspace, default and small model, currency, auto-compaction, subagent limit |
|
| `[server]` | workspace, default and small model, currency, auto-compaction, subagent limit, `metrics_token` |
|
||||||
| `[providers.<name>]` | `kind = "anthropic" \| "openai"`, `base_url`, `api_key`, `max_concurrency`, `models` |
|
| `[providers.<name>]` | `kind = "anthropic" \| "openai"`, `base_url`, `api_key`, `max_concurrency`, `models` (with prices and `fallback`) |
|
||||||
| `[mcp.<name>]` | `type = "stdio"` (command, args, env) or `"http"` (url, headers) |
|
| `[mcp.<name>]` | `type = "stdio"` (command, args, env) or `"http"` (url, headers) |
|
||||||
| `[permissions]` | `allow` / `ask` / `deny` per tool (globs like `mcp__*`); `bash_rules` for commands |
|
| `[permissions]` | `allow` / `ask` / `deny` per tool (globs like `mcp__*`); `bash_rules` for commands |
|
||||||
| `[agents.<name>]` | modes and subagents: model, tools, `max_parallel`, prompt |
|
| `[agents.<name>]` | modes and subagents: model, tools, `max_parallel`, prompt |
|
||||||
| `[auth]`, `[auth.oidc]` | sign-in, public URL, single sign-on |
|
| `[auth]`, `[auth.oidc]` | sign-in, public URL, single sign-on |
|
||||||
|
| `[sandbox]` | shell sandbox for non-admins (`auto`, `always`, `off`) |
|
||||||
|
| `[backup]`, `[backup.s3]` | daily backups, retention, S3 target |
|
||||||
| `[craft]` | headless browser, screen widths, clean room |
|
| `[craft]` | headless browser, screen widths, clean room |
|
||||||
|
|
||||||
Compound shell commands (`&&`, `;`, `|`) are only auto-allowed when every part is allowed.
|
Compound shell commands (`&&`, `;`, `|`) are only auto-allowed when every part is allowed.
|
||||||
|
|
||||||
## Themes
|
## Themes
|
||||||
|
|
||||||
Pick a **base theme** in *Settings → Interface* and switch **light / dark / auto** there or with
|
Pick a **base theme** in *Settings → General* and switch **light / dark / auto** there or with
|
||||||
the ◐ button in the sidebar (auto follows the system preference). Every base theme has a dark and
|
the theme button in the sidebar (auto follows the system preference). Every base theme has a dark and
|
||||||
a light variant. The palettes come from [zink/trilium-themes](https://git.familie-zink.org/zink/trilium-themes)
|
a light variant. The palettes come from [zink/trilium-themes](https://git.familie-zink.org/zink/trilium-themes)
|
||||||
(MIT, see [`web/src/themes/LICENSE-trilium-themes`](web/src/themes/LICENSE-trilium-themes)), which
|
(MIT, see [`web/src/themes/LICENSE-trilium-themes`](web/src/themes/LICENSE-trilium-themes)), which
|
||||||
in turn are based on:
|
in turn are based on:
|
||||||
@@ -224,33 +298,44 @@ cd server && CODECRAFT_CONFIG=../data/config.toml cargo run
|
|||||||
|
|
||||||
# frontend with hot reload, proxies /api to 127.0.0.1:8787
|
# frontend with hot reload, proxies /api to 127.0.0.1:8787
|
||||||
cd web && npm install && npm run dev
|
cd web && npm install && npm run dev
|
||||||
|
|
||||||
|
# terminal client
|
||||||
|
cargo run -p codecraft-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests: `cd server && cargo test` · type check: `cd web && npx tsc --noEmit`.
|
Tests: `cargo test --workspace` · type check: `cd web && npx tsc --noEmit`.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
core/ shared crate: types, config, providers, permissions, prompts
|
||||||
server/ Rust (axum, tokio)
|
server/ Rust (axum, tokio)
|
||||||
runner.rs agent loop: streaming, tools, permissions, subagents, compaction
|
runner.rs agent loop: streaming, tools, permissions, subagents, compaction
|
||||||
provider/ Anthropic and OpenAI-compatible streaming clients, concurrency slots
|
tools/ built-in tools (files, shell, web, browser, agent, craft)
|
||||||
tools/ built-in tools (files, shell, web, agent, craft)
|
|
||||||
mcp.rs MCP client (stdio, Streamable HTTP, elicitation)
|
mcp.rs MCP client (stdio, Streamable HTTP, elicitation)
|
||||||
auth.rs users, sessions, OpenID Connect
|
jobs.rs automations and webhooks
|
||||||
prompts.rs modes, system prompt, AGENTS.md, commands, skills
|
auth.rs users, sessions, API tokens, OpenID Connect
|
||||||
|
cli/ terminal client (ratatui)
|
||||||
web/ React + Vite PWA
|
web/ React + Vite PWA
|
||||||
src/components chat, composer, cards, settings, statistics
|
src/components chat, composer, cards, settings, statistics
|
||||||
src/themes CSS themes
|
src/themes CSS themes
|
||||||
src/i18n English (reference) and German
|
src/i18n English (reference) and German
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The Docker build cross-compiles the server with
|
||||||
|
[cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild), so a multi-arch image builds
|
||||||
|
quickly on either architecture:
|
||||||
|
`docker buildx build --platform linux/amd64,linux/arm64 -t <registry>/codecraft:<version> --push .`
|
||||||
|
|
||||||
Translations: copy `web/src/i18n/en.ts`, translate the values and register the language in
|
Translations: copy `web/src/i18n/en.ts`, translate the values and register the language in
|
||||||
`web/src/i18n/index.ts` – the type checker reports missing keys.
|
`web/src/i18n/index.ts` – the type checker reports missing keys.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Early alpha. Planned next:
|
Early, but in daily use. See the [changelog](CHANGELOG.md). Planned next:
|
||||||
|
|
||||||
- Per-user sandboxes for shell commands
|
- Prebuilt terminal client binaries (Linux, macOS, Windows)
|
||||||
- File checkpoints and undo, background shells, `@file` mentions
|
|
||||||
- MCP OAuth, resources and prompts
|
- MCP OAuth, resources and prompts
|
||||||
- Hooks before/after tool calls
|
- The OpenAI Responses API
|
||||||
- Image generation tools (fal.ai) and the OpenAI Responses API
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE) © Richard Zink. The theme palettes keep the licenses listed under [Themes](#themes).
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# CodeCraft from the published image (amd64 and arm64) – no build needed.
|
||||||
|
#
|
||||||
|
# curl -fsSLO https://git.familie-zink.org/zink/codecraft/raw/branch/main/docker-compose.release.yml
|
||||||
|
# curl -fsSLO https://git.familie-zink.org/zink/codecraft/raw/branch/main/docker/seccomp-sandbox.json --create-dirs --output-dir docker
|
||||||
|
# curl -fsSL https://git.familie-zink.org/zink/codecraft/raw/branch/main/.env.example -o .env # then edit .env
|
||||||
|
# docker compose -f docker-compose.release.yml up -d
|
||||||
|
# docker compose -f docker-compose.release.yml logs codecraft # one-time setup code for the first admin
|
||||||
|
#
|
||||||
|
# Update: docker compose -f docker-compose.release.yml pull && docker compose -f docker-compose.release.yml up -d
|
||||||
|
#
|
||||||
|
# Persistent state lives in the named volume "codecraft-data" (mounted at /data):
|
||||||
|
# /data/config.toml configuration (also editable in the web UI)
|
||||||
|
# /data/codecraft.db sessions, messages, statistics
|
||||||
|
# /data/backups daily backups
|
||||||
|
# /data/home home directory of the agent (git config, caches, ...)
|
||||||
|
services:
|
||||||
|
codecraft:
|
||||||
|
# Pin a version (e.g. :0.1.0) or follow :latest.
|
||||||
|
image: git.familie-zink.org/zink/codecraft:${CODECRAFT_VERSION:-latest}
|
||||||
|
container_name: codecraft
|
||||||
|
restart: unless-stopped
|
||||||
|
# Same UID/GID as the owner of your project files.
|
||||||
|
user: "${UID:-1000}:${GID:-1000}"
|
||||||
|
# Bound to localhost by default: expose it through a TLS reverse proxy.
|
||||||
|
# Set BIND_ADDR=0.0.0.0 to publish it on all interfaces.
|
||||||
|
ports:
|
||||||
|
- "${BIND_ADDR:-127.0.0.1}:${PORT:-8787}:8787"
|
||||||
|
# All variables from .env are available to the config as ${NAME}
|
||||||
|
# (provider keys, MCP tokens, OIDC secret, initial admin).
|
||||||
|
env_file:
|
||||||
|
- path: .env
|
||||||
|
required: false
|
||||||
|
volumes:
|
||||||
|
- codecraft-data:/data
|
||||||
|
# The projects the agents may work on.
|
||||||
|
- ${WORKSPACE:-./workspace}:/workspace
|
||||||
|
# Reach self-hosted models (Ollama, vLLM, ...) on the host.
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
shm_size: "1gb" # Chromium (craft mode, browser tool)
|
||||||
|
# Shell commands of non-admin users run in a bubblewrap sandbox. It needs
|
||||||
|
# user namespaces: a seccomp profile that adds exactly those syscalls to
|
||||||
|
# Docker's default, AppArmor relaxed for the namespace mounts, and an
|
||||||
|
# unmasked /proc so the sandbox can mount its own (hiding server processes).
|
||||||
|
# Remove these three lines and set [sandbox] mode = "off" if you are the
|
||||||
|
# only user.
|
||||||
|
security_opt:
|
||||||
|
- seccomp=./docker/seccomp-sandbox.json
|
||||||
|
- apparmor=unconfined
|
||||||
|
- systempaths=unconfined
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
codecraft-data:
|
||||||
|
name: codecraft-data
|
||||||
@@ -3,6 +3,8 @@ name = "codecraft"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "Web-based coding harness for AI models"
|
description = "Web-based coding harness for AI models"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://git.familie-zink.org/zink/codecraft"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codecraft-core = { path = "../core" }
|
codecraft-core = { path = "../core" }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ case "$arch" in
|
|||||||
esac
|
esac
|
||||||
case "$os" in
|
case "$os" in
|
||||||
linux) ;;
|
linux) ;;
|
||||||
*) echo "codecraft: no prebuilt binary for $os yet – build from source: cargo install --git <repo> codecraft-cli" >&2; exit 1 ;;
|
*) echo "codecraft: no prebuilt binary for $os yet – build from source: cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli" >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
target="$os-$arch"
|
target="$os-$arch"
|
||||||
@@ -24,10 +24,16 @@ url="$SERVER/cli/download/$target"
|
|||||||
mkdir -p "$DIR"
|
mkdir -p "$DIR"
|
||||||
tmp="$DIR/.codecraft.download"
|
tmp="$DIR/.codecraft.download"
|
||||||
echo "Downloading codecraft ($target) from $SERVER …"
|
echo "Downloading codecraft ($target) from $SERVER …"
|
||||||
|
no_build() {
|
||||||
|
rm -f "$tmp"
|
||||||
|
echo "codecraft: this server has no prebuilt binary for $target." >&2
|
||||||
|
echo "Build it from source (needs Rust): cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
if command -v curl >/dev/null 2>&1; then
|
if command -v curl >/dev/null 2>&1; then
|
||||||
curl -fsSL "$url" -o "$tmp"
|
curl -fsSL "$url" -o "$tmp" || no_build
|
||||||
elif command -v wget >/dev/null 2>&1; then
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
wget -q "$url" -O "$tmp"
|
wget -q "$url" -O "$tmp" || no_build
|
||||||
else
|
else
|
||||||
echo "codecraft: needs curl or wget" >&2; exit 1
|
echo "codecraft: needs curl or wget" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
+8
-1
@@ -180,6 +180,13 @@ fn cli_dir() -> PathBuf {
|
|||||||
std::env::var("CODECRAFT_CLI_DIR").map(PathBuf::from).unwrap_or_else(|_| PathBuf::from("/app/cli"))
|
std::env::var("CODECRAFT_CLI_DIR").map(PathBuf::from).unwrap_or_else(|_| PathBuf::from("/app/cli"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this server ships prebuilt terminal client binaries (the release image does not).
|
||||||
|
pub(crate) fn cli_builds_available() -> bool {
|
||||||
|
std::fs::read_dir(cli_dir()).map(|mut d| d.any(|e| e.is_ok_and(|e| e.file_name().to_string_lossy().starts_with("codecraft-")))).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CLI_SOURCE_HINT: &str = "build it from source: cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli";
|
||||||
|
|
||||||
/// The server's public base URL (config, else from the request).
|
/// The server's public base URL (config, else from the request).
|
||||||
fn public_base(app: &App, headers: &axum::http::HeaderMap) -> String {
|
fn public_base(app: &App, headers: &axum::http::HeaderMap) -> String {
|
||||||
let cfg = app.config();
|
let cfg = app.config();
|
||||||
@@ -213,7 +220,7 @@ async fn cli_download(Path(target): Path<String>) -> Response {
|
|||||||
bytes,
|
bytes,
|
||||||
)
|
)
|
||||||
.into_response(),
|
.into_response(),
|
||||||
Err(_) => (StatusCode::NOT_FOUND, format!("no codecraft build for {target} on this server")).into_response(),
|
Err(_) => (StatusCode::NOT_FOUND, format!("no prebuilt codecraft for {target} on this server – {CLI_SOURCE_HINT}\n")).into_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ pub async fn info(State(app): State<Arc<App>>, headers: HeaderMap) -> Json<Value
|
|||||||
"commit": crate::update::commit(),
|
"commit": crate::update::commit(),
|
||||||
"update": if user.as_ref().is_some_and(|u| u.is_admin()) { app.update.latest.lock().unwrap().clone() } else { None },
|
"update": if user.as_ref().is_some_and(|u| u.is_admin()) { app.update.latest.lock().unwrap().clone() } else { None },
|
||||||
"setup_required": app.setup_code.lock().unwrap().is_some(),
|
"setup_required": app.setup_code.lock().unwrap().is_some(),
|
||||||
|
"cli_builds": crate::api::cli_builds_available(),
|
||||||
"oidc": if cfg.auth.oidc.enabled { json!({"label": cfg.auth.oidc.button_label}) } else { Value::Null },
|
"oidc": if cfg.auth.oidc.enabled { json!({"label": cfg.auth.oidc.button_label}) } else { Value::Null },
|
||||||
"user": user,
|
"user": user,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "codecraft-web",
|
"name": "codecraft-web",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { useT } from "../../i18n";
|
import { useT } from "../../i18n";
|
||||||
import { toast } from "../../dialogs";
|
import { toast } from "../../dialogs";
|
||||||
import { Icon } from "../Icon";
|
import { Icon } from "../Icon";
|
||||||
|
import { useFetch } from "../../hooks";
|
||||||
|
import type { Info } from "../../types";
|
||||||
|
|
||||||
/** How to install and use the terminal client. */
|
/** How to install and use the terminal client. */
|
||||||
export function CliInstall() {
|
export function CliInstall() {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const cmd = `curl -fsSL ${location.origin}/cli/install.sh | sh`;
|
const prebuilt = useFetch<Info>("/info").data?.cli_builds ?? false;
|
||||||
|
const cmd = prebuilt
|
||||||
|
? `curl -fsSL ${location.origin}/cli/install.sh | sh`
|
||||||
|
: "cargo install --locked --git https://git.familie-zink.org/zink/codecraft codecraft-cli";
|
||||||
const copy = (s: string) => navigator.clipboard.writeText(s).then(() => toast(t("tokens.copied"), "success"));
|
const copy = (s: string) => navigator.clipboard.writeText(s).then(() => toast(t("tokens.copied"), "success"));
|
||||||
return (
|
return (
|
||||||
<div className="panel">
|
<div className="panel">
|
||||||
@@ -17,7 +22,7 @@ export function CliInstall() {
|
|||||||
</div>
|
</div>
|
||||||
<ol className="cli-steps">
|
<ol className="cli-steps">
|
||||||
<li>
|
<li>
|
||||||
{t("cli.step1")}
|
{t(prebuilt ? "cli.step1" : "cli.step1Source")}
|
||||||
<div className="row" style={{ gap: 6, marginTop: 4 }}>
|
<div className="row" style={{ gap: 6, marginTop: 4 }}>
|
||||||
<code className="token-value">{cmd}</code>
|
<code className="token-value">{cmd}</code>
|
||||||
<button className="small" onClick={() => copy(cmd)}>
|
<button className="small" onClick={() => copy(cmd)}>
|
||||||
@@ -36,9 +41,11 @@ export function CliInstall() {
|
|||||||
</li>
|
</li>
|
||||||
<li>{t("cli.step3")}</li>
|
<li>{t("cli.step3")}</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
{prebuilt && (
|
||||||
<div className="hint">
|
<div className="hint">
|
||||||
{t("cli.downloads")} <a href="/cli/download/linux-x86_64">Linux x86_64</a> · <a href="/cli/download/linux-aarch64">Linux arm64</a>
|
{t("cli.downloads")} <a href="/cli/download/linux-x86_64">Linux x86_64</a> · <a href="/cli/download/linux-aarch64">Linux arm64</a>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -391,6 +391,7 @@ export const de: Messages = {
|
|||||||
"cli.title": "Terminal-Client",
|
"cli.title": "Terminal-Client",
|
||||||
"cli.intro": "Arbeite mit CodeCraft im Terminal wie mit Claude Code: Der Agent bearbeitet Dateien und führt Befehle auf deinem Rechner aus, Modelle, Modi und Regeln kommen von diesem Server (Kosten erscheinen in deiner Statistik). Er läuft auch ohne Server mit eigenen API-Keys.",
|
"cli.intro": "Arbeite mit CodeCraft im Terminal wie mit Claude Code: Der Agent bearbeitet Dateien und führt Befehle auf deinem Rechner aus, Modelle, Modi und Regeln kommen von diesem Server (Kosten erscheinen in deiner Statistik). Er läuft auch ohne Server mit eigenen API-Keys.",
|
||||||
"cli.step1": "Installieren (Linux, x86_64 und arm64):",
|
"cli.step1": "Installieren (Linux, x86_64 und arm64):",
|
||||||
|
"cli.step1Source": "Aus dem Quellcode installieren (braucht Rust; dieser Server hat keine fertigen Binaries):",
|
||||||
"cli.step2": "Mit deinem CodeCraft-Konto anmelden:",
|
"cli.step2": "Mit deinem CodeCraft-Konto anmelden:",
|
||||||
"cli.step3": "Im Projektordner mit `codecraft` starten. Darin: /help, /model, /mode, Shift+Tab wechselt den Modus, @ fügt Dateien hinzu. `codecraft update` aktualisiert.",
|
"cli.step3": "Im Projektordner mit `codecraft` starten. Darin: /help, /model, /mode, Shift+Tab wechselt den Modus, @ fügt Dateien hinzu. `codecraft update` aktualisiert.",
|
||||||
"cli.downloads": "Direkte Downloads:",
|
"cli.downloads": "Direkte Downloads:",
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ export const en = {
|
|||||||
"cli.title": "Terminal client",
|
"cli.title": "Terminal client",
|
||||||
"cli.intro": "Work with CodeCraft in your terminal like with Claude Code: the agent edits files and runs commands on your machine, while models, modes and rules come from this server (costs show up in your statistics). It can also run without a server using your own API keys.",
|
"cli.intro": "Work with CodeCraft in your terminal like with Claude Code: the agent edits files and runs commands on your machine, while models, modes and rules come from this server (costs show up in your statistics). It can also run without a server using your own API keys.",
|
||||||
"cli.step1": "Install (Linux, x86_64 and arm64):",
|
"cli.step1": "Install (Linux, x86_64 and arm64):",
|
||||||
|
"cli.step1Source": "Install from source (needs Rust; this server has no prebuilt binaries):",
|
||||||
"cli.step2": "Sign in with your CodeCraft account:",
|
"cli.step2": "Sign in with your CodeCraft account:",
|
||||||
"cli.step3": "Start it in a project folder with `codecraft`. Inside: /help, /model, /mode, Shift+Tab switches the mode, @ adds files. `codecraft update` updates it.",
|
"cli.step3": "Start it in a project folder with `codecraft`. Inside: /help, /model, /mode, Shift+Tab switches the mode, @ adds files. `codecraft update` updates it.",
|
||||||
"cli.downloads": "Direct downloads:",
|
"cli.downloads": "Direct downloads:",
|
||||||
|
|||||||
@@ -193,6 +193,8 @@ export interface Info {
|
|||||||
/** Newer release (admins only). */
|
/** Newer release (admins only). */
|
||||||
update?: { version: string; url: string; notes: string } | null;
|
update?: { version: string; url: string; notes: string } | null;
|
||||||
setup_required: boolean;
|
setup_required: boolean;
|
||||||
|
/** Prebuilt terminal client binaries can be downloaded from this server. */
|
||||||
|
cli_builds?: boolean;
|
||||||
oidc: { label: string } | null;
|
oidc: { label: string } | null;
|
||||||
user: User | null;
|
user: User | null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user