Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ where a record's file path is its URI:
| `ll [<uri-prefix>]` | list what is already on disk under a prefix |
| `graph <uri> [--depth N] [--format dot\|json]` | walk links and print the subgraph |
| `serve [--addr :7777]` | a dereference server: HTTP GET on a URI returns its record |
| `tui [<uri>]` | a full-screen terminal browser over the namespace, keyboard-driven |
| `mcp` | the same namespace as an MCP tool set for agents |

## Walkthrough
Expand Down
1 change: 1 addition & 0 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ lives on.
newLLCmd(),
newGraphCmd(),
newServeCmd(),
newTUICmd(),
newMCPCmd(),
newDomainsCmd(),
)
Expand Down
41 changes: 41 additions & 0 deletions cli/tui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cli

import (
"github.com/spf13/cobra"

"github.com/tamnd/ant/tui"
)

func newTUICmd() *cobra.Command {
cmd := &cobra.Command{
Use: "tui [uri]",
Short: "Full-screen terminal browser over the URI namespace",
Long: `tui opens the ant terminal console: a full-screen, keyboard-driven browser
over the whole resource-URI namespace. It is the third human surface beside the
CLI and the web console, sharing their vocabulary and keymap. Every screen is a
thin render of an Engine method, so it follows links, lists members, walks the
graph, and browses the on-disk cache without leaving the terminal.

ant tui
ant tui goodreads://book/2767052
ant tui "https://x.com/nasa"

Press ? for the keymap, : to jump to any record, q to quit.`,
Args: cobra.MaximumNArgs(1),
RunE: func(c *cobra.Command, args []string) error {
e, err := engineFrom()
if err != nil {
return err
}
// Warm the in-memory listing index off the render loop, so the first
// dashboard or browse count comes from memory, not a cold walk.
go e.WarmIndex()
initial := ""
if len(args) == 1 {
initial = args[0]
}
return tui.Run(c.Context(), e, tui.Build{Version: Version, Commit: Commit, Date: Date}, initial)
},
}
return cmd
}
1 change: 1 addition & 0 deletions docs/content/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ A record's file path under `--data` is its URI:
| Command | What it does |
|---|---|
| `serve [--addr :7777]` | dereference server: HTTP GET on a URI path returns its record; `/resolve`, `/url`, `/ls`, `/links` endpoints |
| `tui [<uri>]` | full-screen terminal browser over the namespace: follow links, list members, walk the graph, browse the cache, all keyboard-driven |
| `mcp` | the same namespace as an MCP tool set over stdio: get/ls/links/url/resolve/domains |
| `version` | print the version and exit |

Expand Down
2 changes: 1 addition & 1 deletion docs/content/release-notes/v0.2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "v0.2.0"
linkTitle: "v0.2.0"
description: "The web console: browse the whole URI namespace in a browser, with no page that hangs."
weight: 10
weight: 20
---

`v0.2.0` turns `ant serve` from a one-route JSON endpoint into a full **web
Expand Down
87 changes: 87 additions & 0 deletions docs/content/release-notes/v0.3.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: "v0.3.0"
linkTitle: "v0.3.0"
description: "The terminal console: browse the whole URI namespace without leaving the terminal."
weight: 10
---

`v0.3.0` adds `ant tui`, a full-screen **terminal console** over the entire
`ant` URI namespace. It is the third human surface beside the CLI and the web
console, and it shares their vocabulary and their keymap. Every screen is a thin
render of the same engine the other surfaces read, so it follows links, lists
members, walks the graph, and browses the on-disk cache without ever leaving the
terminal.

Nothing else changed: the CLI verbs, the JSON envelope, and the web console are
all exactly as they were in `v0.2.0`.

## The terminal console

Run `ant tui` for the dashboard, or `ant tui <uri>` to open straight onto a
record:

```
ant tui
ant tui goodreads://book/2767052
ant tui "https://x.com/nasa"
```

It is keyboard-driven and discoverable. Press `?` for the full keymap, `:` to
jump to any record from anywhere, and `q` to quit. The screens mirror the web
console one for one:

- **Dashboard** lists every registered domain, the place you land.
- **Domain** is one driver's home: its aliases, hosts, site, and repo, a few
example records to open, and what is already cached under it.
- **Resource** renders a record's envelope with `data`, `body`, and `raw` modes
you cycle through, and a links pane you can step into and follow across sites.
- **Collection** lists the members of a collection URI, and **links** lists the
outbound edges of a record.
- **Search** gives every domain that supports it a query box, and each hit opens
its record.
- **Graph** walks the links to a depth you pick and shows the subgraph as an
indented tree, with a DOT view a keystroke away.
- **Browse** walks the on-disk data tree as a plain folder hierarchy, so you can
see exactly what `ant` already knows without typing a URI.

An **omnibox** (`:`) runs whatever you type through `resolve`, so a bare id, a
handle, a live URL, or a full URI all land on a record. It also understands the
`browse`, `domain`, `search`, `ls`, `graph`, and `links` verbs, so the whole
command surface is one keystroke away.

## Back and forward that actually go back

The console keeps a back and forward stack of whole screens, not just URLs.
Going back restores a screen exactly as you left it: the same scroll position,
the same selected row, the same loaded data. Forward returns you to where you
were.

## Cache-first, and nothing hangs

The read path is the same one the web console uses, so it has the same
guarantees. A record already on disk paints instantly with no network. A miss
fills in from a background fetch with the work kept off the render loop, so the
interface never freezes while a slow site answers. Viewing a record quietly
warms the records it links to, so the likely next screen is often already there.

The console is read-only and local-first. It holds no credentials and changes
nothing on the network. The on-disk data tree is the only state, and the console
reads it freely and writes it only through the explicit export action.

## Install and upgrade

Every tagged version builds the same artifacts: archives for Linux, macOS,
Windows, and FreeBSD, Linux packages (deb, rpm, apk), a multi-arch container
image on GHCR, and package-manager entries. The binaries are pure Go, so there
is nothing to install alongside them.

```
go install github.com/tamnd/ant/cmd/ant@v0.3.0
```

Or grab a binary from the [release
page](https://github.com/tamnd/ant/releases/tag/v0.3.0), or pull the image:

```
docker run --rm -it ghcr.io/tamnd/ant:0.3.0 tui
```
41 changes: 31 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,29 @@ require (
github.com/tamnd/x-cli v0.2.0
)

require github.com/yuin/goldmark v1.8.2
require (
charm.land/bubbles/v2 v2.1.0
charm.land/bubbletea/v2 v2.0.7
github.com/charmbracelet/glamour v1.0.0
github.com/yuin/goldmark v1.8.2
)

require (
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/yuin/goldmark-emoji v1.0.6 // indirect
golang.org/x/term v0.44.0 // indirect
)

require (
github.com/dlclark/regexp2/v2 v2.2.1 // indirect
Expand All @@ -21,25 +43,24 @@ require (
)

require (
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410 // indirect
charm.land/lipgloss/v2 v2.0.4
github.com/PuerkitoBio/goquery v1.12.0 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/charmbracelet/colorprofile v0.3.3 // indirect
github.com/charmbracelet/ultraviolet v0.0.0-20251106190538-99ea45596692 // indirect
github.com/charmbracelet/x/ansi v0.11.0 // indirect
github.com/charmbracelet/colorprofile v0.4.3 // indirect
github.com/charmbracelet/ultraviolet v0.0.0-20260525132238-948f4557a654 // indirect
github.com/charmbracelet/x/ansi v0.11.7 // indirect
github.com/charmbracelet/x/exp/charmtone v0.0.0-20250603201427-c31516f43444 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/charmbracelet/x/termios v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.4.1 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/clipperhouse/displaywidth v0.11.0 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.23 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/mango v0.1.0 // indirect
github.com/muesli/mango-cobra v1.2.0 // indirect
Expand Down
Loading
Loading