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
114 changes: 114 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# AGENTS.md β€” lnk

LinkedIn CLI built on the reverse-engineered Voyager API (Android APK). Go 1.26+, Cobra, RestLi encoding.

## Structure

```
.
β”œβ”€β”€ cmd/
β”‚ └── lnk/
β”‚ └── main.go # Entry point β€” wires Cobra root command and version injection
β”œβ”€β”€ internal/
β”‚ β”œβ”€β”€ api/ # LinkedIn Voyager API client
β”‚ β”‚ β”œβ”€β”€ client.go # HTTP client, cookie jar, base request helpers
β”‚ β”‚ β”œβ”€β”€ rest.go # RestLi protocol helpers
β”‚ β”‚ β”œβ”€β”€ jobs.go # Job search endpoint
β”‚ β”‚ β”œβ”€β”€ jobdetail.go # Single job detail fetch
β”‚ β”‚ β”œβ”€β”€ apply.go # Easy Apply submission
β”‚ β”‚ β”œβ”€β”€ filters.go # Search filter encoding
β”‚ β”‚ β”œβ”€β”€ post.go # Feed/post fetching
β”‚ β”‚ β”œβ”€β”€ profile.go # Profile endpoint
β”‚ β”‚ └── saved.go # Saved jobs management
β”‚ β”œβ”€β”€ auth/
β”‚ β”‚ └── store.go # Cookie persistence (li_at + JSESSIONID) via TOML
β”‚ β”œβ”€β”€ cmd/ # Cobra sub-command implementations
β”‚ β”‚ β”œβ”€β”€ auth.go # lnk auth login/logout/status
β”‚ β”‚ β”œβ”€β”€ search.go # lnk search
β”‚ β”‚ β”œβ”€β”€ job.go # lnk job <id>
β”‚ β”‚ β”œβ”€β”€ apply.go # lnk apply <id>
β”‚ β”‚ β”œβ”€β”€ profile.go # lnk profile
β”‚ β”‚ β”œβ”€β”€ saved.go # lnk saved
β”‚ β”‚ β”œβ”€β”€ alerts.go # lnk alerts
β”‚ β”‚ β”œβ”€β”€ feed.go # lnk feed
β”‚ β”‚ β”œβ”€β”€ status.go # lnk status
β”‚ β”‚ └── helpers.go # Shared output helpers (table + JSON)
β”‚ β”œβ”€β”€ config/
β”‚ β”‚ └── config.go # Config file path resolution
β”‚ β”œβ”€β”€ html/
β”‚ β”‚ └── html.go # HTML tag stripper for job descriptions
β”‚ β”œβ”€β”€ output/
β”‚ β”‚ └── output.go # Table and --json renderer
β”‚ β”œβ”€β”€ restli/
β”‚ β”‚ └── encoder.go # RestLi variable encoding (LinkedIn-specific protocol)
β”‚ └── types/ # Shared domain types
β”‚ β”œβ”€β”€ jobs.go
β”‚ β”œβ”€β”€ profile.go
β”‚ β”œβ”€β”€ alert.go
β”‚ β”œβ”€β”€ urn.go
β”‚ └── errors.go
β”œβ”€β”€ docs/
β”‚ └── assets/ # Banner and hero images (README only)
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ β”œβ”€β”€ ci.yml # Lint + test on push / PR
β”‚ └── release.yml # Cross-platform build + GitHub Release + Homebrew tap
β”œβ”€β”€ api-reference.json # Reference snapshot of Voyager API (NOT a runtime dep)
β”œβ”€β”€ prd.json # Product requirements snapshot (NOT a runtime dep)
β”œβ”€β”€ API-REFERENCE.md # Human-readable API reference
β”œβ”€β”€ go.mod / go.sum
β”œβ”€β”€ Makefile
└── .golangci.yml
```

## Build / Test / Lint

```bash
# Run the full CI gate (vet + fmt check + race tests β€” mirrors ci.yml)
make ci

# Run linter (golangci-lint if installed, falls back to go vet)
make lint

# Run tests with race detector
make test

# Build the lnk binary into the repo root
make build

# Format all Go source files with gofmt
make fmt

# Remove compiled binary
make clean
```

> **Run locally before every commit:** `make ci` must pass cleanly β€” CI enforces the same checks.

## Key Design Decisions

- **RestLi encoding** β€” LinkedIn's Voyager API uses a custom RestLi variable syntax. `internal/restli/encoder.go` handles this encoding. Do not replace it with plain query-string encoding; the API will reject requests.
- **Cookie auth** β€” Authentication uses `li_at` and `JSESSIONID` session cookies, not OAuth. Cookies are stored in a TOML file via `internal/auth/store.go`. Do not introduce OAuth flows.
- **HTML stripping** β€” Job descriptions from the API contain raw HTML. `internal/html/html.go` strips tags before display. Keep this layer; removing it exposes raw markup to the terminal.
- **Cobra + table/JSON output** β€” All sub-commands use Cobra. Every command that returns data must support `--json` for machine-readable output. The `internal/output` package handles both table and JSON rendering consistently.

## Constraints

- **Do not switch from Cobra** β€” the CLI surface, completion, and help text all depend on it.
- **Do not add OAuth** β€” the tool is intentionally cookie-based; OAuth would require an official LinkedIn app registration.
- **Do not remove or rewrite the RestLi encoder** β€” `internal/restli/encoder.go` is a correctness-critical component. Changes must be validated against the existing encoder tests.
- **`prd.json` and `api-reference.json` are reference docs, not runtime deps** β€” they are checked in for developer reference. Do not import or parse them at runtime.
- **Keep `--json` on every data command** β€” machine-readability is a first-class feature. New commands that return data must include a `--json` flag.

## CI

| Workflow | Trigger | Steps |
|----------|---------|-------|
| `ci.yml` | push to `main`, every PR | `go vet`, gofmt check, `go test -race ./...` |
| `release.yml` | push of `v*` tag | cross-platform build (darwin/linux Γ— arm64/amd64) β†’ GitHub Release β†’ Homebrew tap update |

Run the CI gate locally with:

```bash
make ci
```
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

(nothing yet)

## 0.1.0 (2026-06-08)

- Initial release
Expand Down