TIENDocumentation
Docs/Start here

Getting started

Tien is a local-first security CLI for people and AI agents working on JavaScript and TypeScript applications. It combines secret detection, dependency checks, static analysis, and passive checks of web surfaces into evidence you can read, compare, or pass to another tool.

Tien does not exploit targets and it does not replace a penetration test. Repository scans run locally through installed tools or Docker. Every public URL scan requires a scoped, expiring authorization for the exact target hostname.

What you need

  • macOS or Linux
  • Go 1.23 or newer when building from source
  • Git
  • Either Docker, or local installations of Gitleaks, OSV-Scanner, and Semgrep

The default hybrid engine mode uses locally installed scanners when available and falls back to Docker.

Install from source

git clone https://github.com/seibel777/tien.app.git
cd tien.app
go build -o tien ./cmd/tien
./tien --help

To make the command available everywhere on macOS or Linux:

install -m 0755 ./tien /usr/local/bin/tien
tien version

You can also use go install github.com/seibel777/tien.app/cmd/tien@latest. Homebrew, npm, and prebuilt binaries depend on a corresponding release artifact being published.

Connect an AI coding agent

Tien includes a local MCP server. Configure an MCP-compatible agent to start:

tien mcp --root /absolute/path/to/your-app --config /operator-owned/tien.yaml

The agent receives typed tools for capabilities, repository scans, authorized URL scans, and scan diffs. Paths cannot escape the selected root and finding evidence is excluded unless explicitly requested. URL execution fails closed until the operator's startup configuration authorizes every target. An explicitly selected missing, unreadable, or invalid --config path fails startup instead of falling back to defaults. Keep the complete config outside agent-writable project files; Tien loads its fields once, and neither scan tool can replace engines, plugins, arguments, or authorization per call. Referenced rules, plugin binaries, ignore files, and mutable image tags are not snapshotted, so protect them from agent writes and pin versions or digests.

MCP does not impose fixed target-count or finding-count ceilings. Its optional max_findings argument only lets a caller request a smaller presentation; omitting it returns all matching findings.

See the AI agent integration guide for client configuration, tool arguments, and the safe review contract.

Scan an app repository

Run this inside the application you want to review:

tien scan repo --path . --format gob > tien-repo.tien
tien report --type text tien-repo.tien

The scan coordinates three engines:

  • Gitleaks looks for exposed secrets and credentials.
  • OSV-Scanner checks dependency lockfiles against known advisories.
  • Semgrep looks for insecure code patterns.

Tien explicitly disables Semgrep's implicit target-size, per-rule timeout, and timeout-threshold filters, so it does not silently skip large or slow files. Operators can still set max_target_bytes, timeout_seconds, and timeout_threshold when local resource constraints require documented budgets.

For a shareable Markdown report:

tien report --type md --group-by severity tien-repo.tien > tien-report.md

For a standalone HTML overview:

tien plot tien-repo.tien > tien-report.html
open tien-report.html

A practical fix loop

  1. Save a baseline before changing the app.
  2. Read high and critical findings first.
  3. Confirm each finding against the actual code before editing.
  4. Fix one related group at a time.
  5. Run Tien again and compare the artifacts.
tien scan repo --path . > before.tien
# review and fix the app
tien scan repo --path . > after.tien
tien diff before.tien after.tien

The diff separates new, fixed, unchanged, and severity-changed findings. This keeps an AI agent or a human reviewer focused on what actually changed.

Scan a deployed web surface

URL scanning is passive and limited to GET and HEAD. Create a file with one authorized URL per line:

https://app.example.com

For a public domain, generate a 256-bit challenge and an exact-host grant:

tien authorize dns --domain app.example.com --valid-for 24h

Repeat --domain in the same command for batches containing multiple hostnames. Tien creates a separate challenge and exact-host grant for every domain.

Publish the printed structured value at _tien-authorization.app.example.com. and use the printed challenge in the operator config:

safety:
  allow_localhost_without_proof: false
  allow_private_ips_without_proof: false
  allow_resolved_private_hosts: [] # private DNS answers require HTTPS + DNS TXT authorization
  proof:
    method: "dns"
    hosts:
      app.example.com: "GENERATED_HOST_SPECIFIC_256_BIT_CHALLENGE"
    scope: "url-scan"
    max_validity_minutes: 1440

Then run:

tien scan url --config /operator-owned/tien.yaml --targets targets.txt --format gob > tien-url.tien
tien report --type text tien-url.tien

The authorization is bound to the exact hostname, its operator-allowlisted 256-bit challenge, url-scan scope, issue time, and expiry. An apex-domain grant does not authorize its subdomains. Each exact hostname in a multi-host batch has a separate challenge. DNS TXT is the only supported authorization method.

The url-scan grant is a cooperative operational signal for Tien's built-in GET/HEAD checks, not legal or contractual authorization. It does not replace written permission or rules of engagement, and a modified binary or fork can remove the check.

Tien authorizes the complete batch before starting workers, cache reads, or built-in target requests. One unauthorized target stops the batch. If the earliest grant expires during execution, Tien aborts with authorization failure; MCP returns a tool error rather than partial success. A batch containing any public target fails closed when a URL plugin is enabled; URL plugins can currently run only for explicitly proof-exempt literal localhost or private-IP development targets. Tien also restricts redirects to the same scheme, hostname, and effective port. Localhost and literal private IPs require separate explicit development exemptions. A hostname that resolves to RFC 1918 or IPv6 ULA space must appear exactly in allow_resolved_private_hosts, use an HTTPS target, and present its exact DNS TXT grant; its resolved addresses are pinned for the scan. Loopback through a non-local name, link-local, CGNAT, multicast, unspecified, and metadata addresses remain blocked.

The scan checks TLS, security headers, cookie flags, CORS signals, security.txt, and mixed-content references. There is no fixed target or finding ceiling. Response size, per-target time, retries, redirects, and concurrency remain configurable resource budgets.

Combine repository and URL evidence

tien merge tien-repo.tien tien-url.tien > tien-full.tien
tien report --type md --group-by source tien-full.tien > tien-full-report.md

Next steps

  • Read the command reference for every command and flag.
  • Add a config file when you need different engines, exclusions, policies, URL authorization, or resource budgets.
  • Use the AI-agent guide to let Codex, Claude Code, Cursor, or another shell-capable agent run Tien safely.
  • Add a policy gate in CI only after reviewing and saving a realistic baseline.