Gå til hovedinnhold

AD-001: Vision and Module Architecture

Summary

neokapi is an open, AI-native content and language intelligence framework in Go, distributed under Apache-2.0. It ships as independent Go modules — framework, the cobra-free host runtime, the thin Cobra shell, the standalone CLI (kapi), and the desktop app (kapi-desktop) — coordinated by a go.work file. Each module has an explicitly declared dependency footprint, enforced by CI with GOWORK=off builds plus make audit-modules.

Context

The framework has to serve several distinct deployment targets from one codebase: a standalone file-processing CLI for engineers, a visual desktop app for content and language specialists, and a library that larger platforms can embed. Each target has a different dependency profile — Wails for the desktop app, keychain access for credentials, SQLite for local stores — and forcing every binary to pull every dependency produces slow builds and bloated artifacts.

At the same time, the framework is the Apache-licensed core of a broader ecosystem. Separately-licensed platforms layered on top of it must build on framework interfaces without polluting the framework with platform-specific dependencies. The license boundary is structural, not conventional: framework code never depends on separately-licensed platform code, and CI enforces it.

Decision

Identity

neokapi is an open-source content and language intelligence framework in Go, licensed under Apache-2.0. It provides format-aware document parsing into one content model, a channel-based concurrent processing engine, faithful write-back, and composable tools for translation, quality assurance, terminology management, and review. Everything is a library and a toolkit — no database, no server, no authentication. The framework is the primary vehicle for open innovation in format support, processing tools, and AI integration.

Design principles:

  1. Streaming concurrency. Documents flow through a pipeline of channels; each tool runs in its own goroutine. See AD-004: Processing Engine.
  2. Content-addressable blocks. Translatable units are identified by the hash of their normalized content plus surrounding context, enabling deduplication across sources and incremental processing. See AD-002: Content Model and AD-003: Identity.
  3. Progressive complexity. A single CLI command on day one, a YAML flow on day two, an integrated project on day ten. The same content model and tool chain work at every scale.
  4. AI as first-class pipeline tools. LLM-powered translation, quality assurance, terminology extraction, and review are ordinary pipeline tools that participate in the same flow execution model as format-aware tools.
  5. Single-binary distribution. Go compiles to static binaries. The shared codebase produces the kapi CLI and the kapi-desktop desktop app with no JVM, no Node.js runtime, and no container required for basic usage.

Framework Modules

These Go modules make up the framework side, coordinated by a single go.work file at the repository root:

ModuleImport pathDirectoryRole
Frameworkgithub.com/neokapi/neokapi. (repo root)Content model, formats, tools, pipeline, plugin system, content memory, terms, AI/MT providers
Hostgithub.com/neokapi/neokapi/hosthost/Cobra-free application runtime + services: app config, credentials, plugin host, flow/convergence/check services
CLIgithub.com/neokapi/neokapi/clicli/Thin Cobra shell over host: command factories, flag registration, dispatch
Kapigithub.com/neokapi/neokapi/kapikapi/Standalone CLI tool for local file processing
Kapi Desktopgithub.com/neokapi/neokapi/kapi-desktopapps/kapi-desktop/Wails v3 desktop app for visual content and translation workflows

The dependency graph is strictly hierarchical. Note that kapi-desktop links neither the cli module nor Cobra — it builds on host directly, which is why the runtime and the command shell are separate modules at all:

frameworkcore/ · no platform depshostruntime + services · no cobrabuild on framework + hostkapiframework + host + clikapi-desktopframework + host · no cli, no cobra

kapi builds on framework + host + cli; kapi-desktop builds on framework + host and links no Cobra. Both blank-import the Apache-2.0 bowrain recipe-schema for recipe validation. CI enforces the boundaries.

Dependency rules

The following invariants are enforced by CI:

  • Framework has zero platform dependencies. No SQLite, Wails, Echo, Cobra, Viper, OIDC, or keyring imports. The framework is pure library code.
  • Host depends only on the framework, and must not import Cobra. Command threading is the host.Command interface (context + *pflag.FlagSet + IO), which *cobra.Command satisfies natively; embedded runs use host.EnvCommand.
  • CLI depends on framework + host. No Wails, Echo, or OIDC. CLI is where Cobra lives.
  • Kapi depends on framework + host + CLI. No heavy dependencies (no Wails, no OIDC).
  • Kapi Desktop depends on framework + host — not on the cli module and not on Cobra — plus the Apache-2.0 bowrain/plugin/schema package, which it blank-imports to validate bowrain recipes on open. The Wails v3 and keyring dependencies justify a separate module so that Kapi CLI builds stay small.
  • No framework engine module depends on any AGPL platform code. core, host, cli, kapi, and kapi-desktop are all Apache-2.0 end-to-end. bowrain/plugin/schema is the recipe vocabulary (typed specs + YAML decoders, importing only the framework) and is itself Apache-2.0, so Kapi Desktop's blank-import of it is not an AGPL edge.

These rules are verified in CI with GOWORK=off builds per module, wrapped up by make audit-modules (which also asserts go mod tidy is a no-op per module, and asserts via go list -deps that the desktop backend is Cobra-free):

GOWORK=off go build ./... # framework
GOWORK=off bash -c "cd host && go build ./..." # host (no cobra)
GOWORK=off bash -c "cd cli && go build ./..." # cli
GOWORK=off bash -c "cd kapi && go build ./..." # kapi
GOWORK=off bash -c "cd apps/kapi-desktop && go build ./backend/..." # kapi-desktop

The desktop build is scoped to ./backend/... because the module's top-level package embeds frontend/dist, which does not exist until the frontend has been built — an unscoped ./... fails on the missing embed before it ever typechecks.

A successful GOWORK=off build per module proves that each module's imports resolve without the workspace — meaning every cross-module import is a real dependency declared in the module's go.mod.

License boundary

All four framework modules are Apache-2.0. The broader repository also hosts a separately-licensed platform, which builds on framework interfaces (content model, tools, flows, formats); the framework engine — core, cli, and kapi — never imports platform code in return. The license gradient is one-directional:

Apache-2.0 frameworkcore · cli · kapiSeparately-licensed platform

The license gradient is one-directional: the separately-licensed platform consumes the Apache-2.0 framework (core · cli · kapi), never the reverse. Kapi Desktop blank-imports bowrain/plugin/schema, which is itself Apache-2.0 recipe vocabulary — not an AGPL edge.

This is a structural property, not a convention. The framework engine — core, cli, and kapi — never imports AGPL platform packages, so accidental upward coupling there is a compile error. Kapi Desktop blank-imports bowrain/plugin/schema to validate bowrain recipes on open, but that package is itself Apache-2.0 recipe vocabulary (typed specs + YAML decoders, importing only the framework), declared in apps/kapi-desktop/go.mod — so the desktop binary links no AGPL code. The framework and both binaries stay Apache-2.0 end-to-end.

Framework package layout

Within the framework module (repo root), packages are grouped by responsibility:

core/
model/ Content model types (Part, Block, Layer, Run, Target, Overlay)
format/ DataFormatReader/Writer interfaces, detection, skeleton
tool/ Tool interface, BaseTool dispatch
flow/ Executor, Builder, FlowDefinition
registry/ FormatRegistry, ToolRegistry
encoding/ Text encoding utilities
locale/ BCP-47 locale handling
editor/ Block index serialization and preview generation
id/ Short base62 ID generation
version/ Build version info
formats/ Built-in format implementations
tools/ Built-in utility tools
ai/ AI pipeline tools (tools/), prompts (prompt/), and NER (ner/)
mt/ MT pipeline tools (tools/)
plugin/ Plugin system: gRPC host, Java bridge, loader, registry
storage/ Shared SQLite DB infrastructure
blockstore/ Block store Session/Store interfaces
project/ .kapi project file format
preset/ Built-in preset definitions
schema/ JSON-schema generation for tool/component parameters
segment/ Segmentation primitives and masking
brand/ Brand-voice model
graph/ Graph data structures
i18n/ Per-locale component schemas and backend metadata
its/ W3C ITS metadata
kbf/ Kapi Bundle Format (.kbf.json) block serialization
redaction/ Span redaction/restoration
ignore/ .kapiignore pattern matching
httputil/ HTTP client helpers
set/ Generic set container
internal/
testutil/ Shared test helpers
memory/ Content memory (interface + in-memory + SQLite + matching)
terms/ Terminology (interface + in-memory + SQLite + import)
providers/
ai/ package aiprovider — LLM providers
mt/ package mtprovider — MT providers
bench/ Benchmarks
examples/ Plugin examples

The list above names the framework's primary package groups rather than enumerating every directory; consult the source tree for the authoritative set.

Workspace and versioning

The root go.work file coordinates the workspace for local development. It lists every module in the repository — the framework modules below plus the separately-licensed platform modules and build-support modules under scripts/. The four framework modules are:

use (
. # framework
./cli # shared CLI base
./kapi # kapi CLI
./apps/kapi-desktop # kapi-desktop
# … plus the platform modules (under bowrain/) and scripts/ helpers
)

With the workspace active, changes to framework code are visible to the CLI, kapi, and kapi-desktop without publishing. go mod tidy does not respect go.work, so each child module's go.mod carries a replace directive pointing to ../ for the parent modules it depends on.

Only the framework module is tagged today, using flat semver tags (vX.Y.Z). The child modules (host, cli, kapi, kapi-desktop, and the platform modules) are not independently tagged. Go's module-version conventions would allow per-module tags (e.g. cli/v0.1.0), but the workspace currently relies on go.work plus replace directives rather than published per-module versions.

All modules target Go 1.26+. The root Makefile provides per-module build, test, vet, and lint targets.

Configuration

The CLI module uses Viper for layered config, with the following precedence (highest wins):

  1. CLI flags (via Cobra) — one-off overrides
  2. Environment variables (KAPI_* prefix) — CI/CD and Docker
  3. Project config (kapi.yaml project files) — workflow defaults
  4. User config (kapi.yaml in the user config directory — ~/.config/kapi on Linux, ~/Library/Application Support/kapi on macOS; kapi config path prints the resolved location) — personal defaults
  5. Code defaults — sensible zero-config behavior

Both kapi and kapi-desktop use Cobra (kapi directly, kapi-desktop indirectly through the shared CLI base) for hierarchical subcommands. Kapi operates directly on files (kapi pseudo-translate file.json); kapi-desktop wraps the same commands behind a GUI.

Locale handling

model.LocaleID is a string typedef holding BCP-47 tags in canonical form (en, fr, pt-BR). The core/locale package provides validation, normalization, and display-name resolution:

func Parse(s string) (model.LocaleID, error)
func MustParse(s string) model.LocaleID
func DisplayName(id model.LocaleID) string
func WellKnownLocales() []LocaleInfo

BCP-47 validation delegates to golang.org/x/text/language, which handles subtag parsing, script inference, and canonicalization. All subsystems (format readers, content-memory entries, terminology, CLI flags) validate locale codes at their boundaries so invalid codes never propagate silently.

Consequences

  • Kapi CLI binary has no Wails, keyring, SQLite server, or OIDC dependencies; it stays small and fast to build.
  • CLI module evolves independently of consumer modules — CLI changes do not force kapi or kapi-desktop rebuilds of unrelated code.
  • Framework packages are organized under core/, memory/, terms/, providers/, giving a clean separation of concerns at the directory level.
  • Four go.mod files need maintenance, but go.work resolves cross-module imports during daily development and the release.yml workflow handles multi-module release builds.
  • License-clean: Apache-2.0 framework modules never accidentally pull separately-licensed platform code, enforced by import-path topology.
  • The shared CLI base lets kapi and kapi-desktop expose identical commands without duplicating command logic.
  • Progressive scalability: the same content model and tool chain works for a solo developer running kapi pseudo-translate on local files and for a team using kapi-desktop with a rich flow editor and plugin manager.