diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 99d9342..61773da 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -89,4 +89,4 @@ jobs: run: | EXT="" if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi - go build -trimpath -o "linksmith${EXT}" ./cmd/linksmith + go build -trimpath -o "linksmith${EXT}" ./cmd/linksmith \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 18db98c..b67bb46 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -86,4 +86,4 @@ jobs: with: files: | dist/*.tar.gz - dist/checksums.txt + dist/checksums.txt \ No newline at end of file diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 12b6c1e..8618ded 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -31,7 +31,7 @@ jobs: else VERSION="0.0.0" fi - echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "Version: $VERSION" - name: Check if tag exists @@ -63,4 +63,4 @@ jobs: repo: context.repo.repo, workflow_id: 'release.yaml', ref: 'v${{ steps.version.outputs.version }}' - }) + }) \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..b9490d9 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,400 @@ + + + + + + LinkSmith โ€” Agentic-First Link Shortener + + + + + + +
+

LinkSmith

+

Agentic-first link shortener. The agent IS the interface.

+
+ Go + Single binary + Zero config + Multi-tenant +
+
+ View on GitHub + Quick Start +
+
+ + +
+

Quick Start

+
# Build the single static binary
+make build
+
+# Run with zero config โ€” starts on :8080
+./linksmith
+
+# Shorten a link
+curl -X POST http://localhost:8080/api/links \
+  -H "Authorization: Bearer <token>" \
+  -d "url=https://example.com"
+
+# Response (plain text, one line per record)
+handle=link_a1b2c url=https://example.com clicks=0
+
+# Redirect (public, no auth needed)
+curl -I http://localhost:8080/l/link_a1b2c
+# โ†’ 301 Location: https://example.com
+
+ + +
+

Principles

+
+
+
๐Ÿค–
+

Agent is the interface

+

No UI, no SDK. The AI agent is the user. The API is the product.

+
+
+
๐Ÿ“
+

Plain text by default

+

One labeled, grepable line per record. Token-cheap, survives context truncation. JSON on demand.

+
+
+
๐Ÿ’ก
+

Instructive errors

+

Every 4xx includes a hint telling the agent what to do next. Self-correcting without a schema.

+
+
+
๐Ÿ“–
+

Self-documenting

+

GET /help returns a one-page operating manual the agent loads at runtime.

+
+
+
๐Ÿ”
+

Simple auth

+

OTP via email โ†’ long-lived bearer token. No complex OAuth flows.

+
+
+
๐Ÿ“ฆ
+

Single static binary

+

Go, zero external dependencies, CGO_ENABLED=0. Deploys as one file.

+
+
+
โš™๏ธ
+

Zero config defaults

+

Runs out of the box. Config layered: defaults < file < env < flags.

+
+
+
๐Ÿข
+

Multi-tenant ready

+

Workspaces isolate links per tenant. Plans, limits, audit logs built in.

+
+
+
+ + +
+

API Reference

+ +

Authentication

+
POST /auth/request   email=<email>&workspace=<handle>  โ†’ OTP code
+POST /auth/verify    email=<email>&code=<code>          โ†’ Bearer token
+ +

Links (requires Bearer token)

+ + + + + + + + + + + +
MethodPathDescription
POST/api/linksCreate a shortened link
GET/api/linksList all links
GET/api/links/<handle>Get link details
DELETE/api/links/<handle>Delete a link
GET/api/workspaceWorkspace info
+ +

Redirect (public, no auth)

+
GET /l/<handle>  โ†’ 301 redirect to original URL
+ +

Response Formats

+
# Plain text (default)
+handle=link_a1b2c url=https://example.com clicks=0
+
+# JSON (add Accept: application/json or ?format=json)
+{"handle":"link_a1b2c","url":"https://example.com","clicks":0}
+
+ + +
+

Configuration

+ + + + + + + + + +
FlagEnv VarDefaultDescription
-addrLINKSMITH_ADDR:8080Listen address
-dbLINKSMITH_DBlinksmith.jsonData file path
-secretLINKSMITH_SECRETrandomToken signing secret
+
+ + +
+

Build

+
make build    # CGO_ENABLED=0, single static binary
+make test     # go test ./...
+make vet      # go vet ./...
+
+ + + + + + \ No newline at end of file