CLI tools
kgrep, ksed, kcat and kdiff are format-aware reimaginings of the classic
Unix text utilities. grep, sed, cat and diff operate on raw bytes: the
lines of a file as the operating system stores them. These four read, rewrite
and compare the text content inside any format kapi understands,
regardless of how that text is encoded on disk. They run on the same content
engine as the rest of kapi.
You can search the prose inside a Word .docx, rewrite a phrase across a
directory of JSON catalogs, or print the segments of an XLIFF file as plain
text, without converting anything first.
kdiff extends the same idea to diff: it compares the text of two
files block by block, so a reflowed .docx or a reordered JSON catalog shows
only the prose that actually changed. Given a single file and a target locale,
it reports which blocks are still untranslated.
A fifth utility, kconv, has no classic Unix analog: it converts
between formats (a .docx to clean Markdown, a DocLang document to HTML, or any
supported format to DocLang), and carries the document's structure across.
The video below shows the whole loop on a sales team's collateral: a Markdown
pitch, a Word proposal, and an Excel price list. kcat prints the text inside
each file, kgrep finds the product name across all three at once, and a single
ksed rebrands it everywhere, rewriting each document back into its own format.
Each works on every one of the 40+ file formats neokapi reads: Office documents, message catalogs and data formats, markup, and more. See the Format Reference for the full list.
Why blocks, not lines
A .docx has no "lines" in the byte sense; a JSON catalog's meaningful units
are keyed strings, not file rows. kapi parses a document into blocks of
content and strips the surrounding markup and structure. The
toolbox operates on those blocks:
kcatprints one block per output line.kgrepreports one matching block per line, and-nprefixes the block's ordinal position. For genuinely line-oriented formats such as plain text, one block is one line, so-nreads exactly likegrep -n.ksedrewrites a block's text and asks the format writer to reconstruct the document, so structure is preserved.kdiffaligns the blocks of two files (by key for catalogs, by content for prose) and reports added, removed, changed and moved blocks.kconvhands the blocks, and the role each one carries (heading, list item, table cell), to a different format's writer, projecting the document's structure into the target format.
Installation
The kapi CLI bundles these commands:
brew install neokapi/tap/kapi-cli # macOS/Linux
See Installation for the release channels.
On Windows, winget install Neokapi.KapiCli installs kapi 1.0.2, which predates
the behaviour described here. Take a Windows build from the
direct downloads instead.
Every utility is also reachable as a kapi subcommand under the same name:
kapi kgrep, kapi ksed, kapi kcat, kapi kdiff, kapi kconv. Each behaves
identically to its short name on every platform. The subcommands keep the
k-names because the bare verbs are taken: kapi diff is the connected-project
sync diff.
The Homebrew install adds the short names (kgrep, ksed, kcat, kdiff,
kconv) as aliases of the kapi binary. The Windows zip carries the single
kapi command, so on Windows use the subcommand form (kapi kgrep,
kapi ksed, kapi kcat, kapi kdiff, kapi kconv), which is exactly
equivalent.
Conventions shared across the toolbox
- Standard input. With no file argument, or when the file is
-, input is read from standard input. Without a file extension to go by, the format is sniffed from the content and falls back to plain text. - Format selection.
-f, --formatoverrides format detection (for example-f json). This differs fromgrep/sed, where-freads patterns or scripts from a file; in the toolbox-falways means format, matching the rest of the kapi CLI. Use-efor explicit patterns and scripts. - Source vs. translation. For multilingual formats the utilities by default
operate on the source text.
--target LOCALEoperates on a target language instead. For example,kgrep --target fr "déconnexion" messages.xliffsearches the French translations. - Files and directories. Glob patterns expand in-process, so a quoted
'src/**/*.md'behaves the same in every shell. A directory argument needs-r, --recursive; without it, it is reported and skipped, as ingrep. The one exception isksed, which spells it-R: sed's own-rmeans--regexp-extended, so the letter is left alone. - Binary input is refused. A file that no format claims and whose bytes are
binary (a
.dmg, an installer, an image with no reader) is reported and skipped, so a glob over a downloads folder cannot write raw bytes to the terminal or into a converted file. Other files in the same run are unaffected, and the exit status is 2.-f FORMAToverrides the guard when you mean it.