|
|
||
|---|---|---|
| .forgejo | ||
| cmd/redakt | ||
| compose | ||
| docs | ||
| internal | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLA.md | ||
| COMMERCIAL-LICENSE.md | ||
| CONTRIBUTING.md | ||
| Dockerfile | ||
| embed.go | ||
| go.mod | ||
| go.sum | ||
| install.sh | ||
| install_test.sh | ||
| LICENSE | ||
| LICENSE-why-affero.html | ||
| LICENSE.header.txt | ||
| Makefile | ||
| MODELNOTES.md | ||
| NOTICE.md | ||
| README.md | ||
| redakt.toml.example | ||
| SECURITY.md | ||
| STYLE.md.example | ||
redakt
Status: scaffold (v0.0.0-scaffold). This commit is the AGPLv3+ dual-licensed FOSS skeleton. The TUI, provider layer, ensemble, style learning, and WriteFreely adapter land in PRs #1–#5. Today's binary prints its version and exits.
Interactive multi-model ensemble blog assistant for Linux.
You write a rough outline. redakt fans it out to N language models
(local + cloud), shows you their rewrites side-by-side in a terminal UI,
remembers what you accept, drifts toward your voice over time, and posts
the finished Markdown to WriteFreely with one keystroke.
Why
I wanted a workflow where:
- the rough outline is mine,
- several models propose rewrites for each section,
- I accept what I like,
- the tool learns what "what I like" means,
- the completed post is one keystroke from WriteFreely.
Nothing I tried scratched this itch. So I built redakt.
Stack
- Language: Go 1.25+
- UI: Bubble Tea + Lipgloss + Bubbles + Huh + Glamour (Charmbracelet:
charm.land). The project's charm-first reuse rule
is documented in AGENTS.md; the file picker that powers
mid-session context loading is
bubbles/filepickerand the inline candidate editor isbubbles/textarea. - Logging:
charmbracelet/logfeeds a secret-scrubbingsloghandler. - LLM clients: OpenAI-compatible (
sashabaranov/go-openai). Works with any OpenAI-style endpoint — local llama-server (viallama-toolcall-proxyfor buggy tool-call emitters), Ollama, Groq, Gemini, OpenRouter, etc. - Style learning:
STYLE.md(you own it) + an accepted-line corpus + a periodic auto-merge proposal you approve before it lands. - Blog backend: WriteFreely (
POST /api/posts), pluggable later.
Build from source
git clone https://git.ourserver.party/xenarathon/redakt.git
cd redakt
make install # builds and installs to $(go env GOPATH)/bin — no sudo
Install — native binary (recommended)
One-liner (downloads, verifies, and installs the right build for your OS/arch; on Linux, also adds a desktop menu entry):
curl -fsSL https://git.ourserver.party/xenarathon/redakt/raw/branch/main/install.sh | sh
Covers linux-amd64, linux-arm64, darwin-amd64, darwin-arm64 — no other CPU
architecture is built today (no ppc64le, i386/i686, or armv6l/armv7l); the
script exits with a named error on anything else rather than guessing.
If you'd rather read the script before piping it to sh (a reasonable habit) — or do it by
hand for any other reason — here are the same steps manually:
# 1. Find the latest release tag (Forgejo has no GitHub-style "latest" URL alias)
TAG=$(curl -s https://git.ourserver.party/api/v1/repos/xenarathon/redakt/releases/latest \
| grep -o '"tag_name":"[^"]*"' | cut -d'"' -f4)
# 2. Download
curl -LO https://git.ourserver.party/xenarathon/redakt/releases/download/$TAG/redakt.linux-amd64.tar.xz
# 3. Verify sha256 (fail-closed)
curl -L https://git.ourserver.party/xenarathon/redakt/releases/download/$TAG/SHA256SUMS \
| grep redakt.linux-amd64.tar.xz | sha256sum -c -
# 4. Install
tar -xJf redakt.linux-amd64.tar.xz
sudo install -m 0755 redakt /usr/local/bin/redakt
# 5. First run
redakt init
darwin/arm64, linux/arm64, and darwin/amd64 builds drop with
matching SHA256SUMS. Optional Homebrew tap lands later.
Trust model: the install path relies on TLS to git.ourserver.party, the SHA256SUMS
file shipped alongside each release, and whoever has Forgejo push access to cut a release — there
are no PGP-signed releases yet. That's a deliberate choice for a single-maintainer, self-hosted
project today, not an oversight.
Docker (optional, for the homelab): see compose/redakt.yaml.
Configure
~/.config/redakt/redakt.toml — see redakt.toml.example for a starting point.
[ensemble]
default_providers = ["nanbeige", "groq", "gemini"]
~/.config/redakt/.env — keep it out of git:
GROQ_API_KEY=...
GEMINI_API_KEY=...
OPENROUTER_API_KEY=...
NANBEIGE_URL=http://192.168.1.209:8094/v1 # local llama-server via the toolcall proxy
WRITEFREELY_INSTANCE=https://blog.ourserver.party
WRITEFREELY_TOKEN=...
Get the WriteFreely token with redakt auth login (lands in PR #3).
Voice guide
~/.config/redakt/STYLE.md is your hand-written style guide. It's the
base of every system prompt; edit it freely — the tool does not
auto-overwrite your manual changes. A starter seed ships in
STYLE.md.example.
Use
redakt new path/to/outline.md # seed the post from an outline
redakt new # start with an empty post
redakt resume # pick up an unfinished post
Inside the TUI:
j/k— navigate candidatesa— accept the selected candidater— re-roll candidates for the current sectionc— open the file picker (bubbles/filepicker) to add context files mid-session. Navigates to.md/.markdown/.txtanywhere on disk and appends to the live post's context — never replaces the--contextlist passed at launch. Navigate into a folder and pressdto add every top-level.md/.markdown/.txtfile in it (non-recursive) instead of a single file —Enteralone can only select a file, never a folder.Esccancels and returns to the candidate review without changes.m— edit the selected candidate inline (Ctrl+Ssave,Esccancel)Ctrl+P— preview the assembled postp(from Reviewing) — enter Publish phasey/n— confirm / reject (publish, style merge, etc.)q— quit; any unsaved post becomes a draft in~/.local/share/redakt/drafts/
How style learning works
Three layers; each is opt-in and reversible.
STYLE.md(you own it). Base of every system prompt.- Accepted corpus (
~/.local/share/redakt/accepted_corpus.jsonl). Every accepted line appended. Last 10 + 5 deterministic-random older entries injected as few-shot examples. Atomic-rename writes; SIGINT-safe. - Periodic auto-merge (every 25 accepts).
redaktruns an internal "reconcile recent corpus + STYLE.md → proposed update" against a stable local provider. The proposal is written tostyle_proposal.mdand you must approve it before it merges intoSTYLE.md. Never silent.
License
redakt is dual-licensed:
- Open source: GNU Affero General Public License, version 3 or later
(see
LICENSE). Strong copyleft with the network clause. - Commercial: available if AGPL terms don't fit. See
COMMERCIAL-LICENSE.md.
Every .go file carries the AGPL SPDX header from
LICENSE.header.txt; enforced by the
make license-check target.
Third-party NOTICE (AGPL §5 compliance)
The redakt binary prints its license + third-party attribution on
demand via redakt license. The full per-dep attribution table —
including transitive dependency licenses — lives in
NOTICE.md at the project root. The AGPL §5 obligation
on interactive user interfaces is satisfied by three surfaces: the
redakt license subcommand, the TUI ?-key banner, and the
NOTICE.md file itself.
Contributors sign a CLA (terms in CONTRIBUTING.md).
Security defaults
The tool never:
- posts to WriteFreely without an explicit keypress and confirmation (a
second confirm when
safer_postingis on, the default), - prints
Authorizationheaders or*_API_KEYto logs, - overwrites your
STYLE.mdsilently.
See CONTRIBUTING.md.
Status
This is the scaffold commit (0.0.0-scaffold). Subsequent PRs land:
- Config layer + XDG + slog with secret scrubbing
- Provider abstraction + ensemble orchestrator
- WriteFreely adapter
- Style learning module
- Bubble Tea TUI
- Tests
- Native release pipeline + optional Homebrew tap
Disclaimer
🤖 This project was built with the help of AI assistants: the scaffold, review, and architecture with Claude (Opus 4.8) by Anthropic, and the implementation PRs with Kimi. All code is human-reviewed before merge.