Portrait

User GuideIntegrations & API

Portrait CLI

Copy for agent

The Portrait CLI puts Easel, Portrait's AI equity analyst, in your terminal. Ask a question, get a cited answer back, and keep the conversation going across commands — without leaving your shell.

It is also built to be driven by an AI coding agent. Every command prints machine-readable JSON, and the package ships an agent skill you can install so your agent knows how to use it correctly.

ℹ️ Using the Portrait CLI requires Easel access on your Portrait account. If a command reports that your account is not enabled, contact the team.

Install

The CLI is published on npm and needs Node.js 20.17 or later.

npm install --global @portrait-research/portrait

Sign in

portrait auth login

The command prints a verification URL and a user code, and tries to open the URL in your default browser. If it cannot, open the printed URL yourself and enter the code — signing in by hand always works. Sign in with your normal Portrait credentials.

Your credentials are stored in your operating system's keyring, not in a file in your home directory. portrait auth status shows whether you are signed in, and portrait auth logout removes the stored credentials.

Ask a question

portrait ask "What did Microsoft management say about AI capex on the last three earnings calls?"

The answer comes back with a session ID. Pass it to a later question to continue the same conversation, with all its context:

portrait ask --session <session-id> "Turn that into a table by quarter."

Two things worth knowing:

  • Always use the session ID from the most recent response. If a session has gone idle, the CLI resumes it for you automatically — and the resumed session gets a new ID, which is returned in that answer.
  • Answers link back into the app. Citations and references in the answer are full links that open the underlying document in Portrait.

Add --stream to watch the answer arrive as it is written instead of waiting for the finished text.

Manage sessions

portrait sessions list [--limit N] [--cursor <cursor>]  # one page of sessions, with titles and previews
portrait sessions history <session-id>                # the turns in one session
portrait sessions create                     # start an empty session
portrait sessions create --resume <id>       # reopen a past session

Use list to find the session you want, history to see what was said in it, then ask --session to carry on. A list request returns one page without automatically loading more. Set --limit from 1 to 50, and request a next page by passing the returned opaque data.next_page_cursor unchanged to --cursor.

Ask for a monitor or a screen

Monitors and screens are ordinary requests — describe the one you want and Easel builds it, coming back to you for confirmation when it needs to.

For a monitor, give the name, the companies, the topics, the sources, how often you want to be notified, and the project it belongs in (or say it should stay unfiled):

portrait ask "Create a monitor named 'Semiconductor Capex Watch' for ASML, AMAT, and LRCX. Track capex guidance and order commentary from earnings calls, filings, and company news; notify in real time; keep it unfiled."

Reading your monitors back changes nothing, so ask freely:

portrait ask "List my monitors with their companies, topics, sources, destinations, unread-update counts, and latest-update times."
portrait ask --session <session-id> "Check 'Semiconductor Capex Watch' and summarize its latest updates. Do not change it or mark updates as read."

A screen stands on its own — it is not filed in a project. Give it a name, the filters, the universe of companies, and either a single run or a recurring cadence with a UTC run time (plus the weekday, for a weekly screen):

portrait ask "Create a one-shot screen named 'Large-Cap Compounders' across all active companies. Use these filters: market cap above $10 billion, positive revenue growth, and positive free cash flow."

A screen run takes several minutes. Ask for the outcome on a later turn in the same session rather than launching it again:

portrait ask --session <session-id> "Check 'Large-Cap Compounders' once. If it is complete, summarize the matching companies and filter results; if it is still running, report only its current status. Do not launch another screen."

If that session has gone idle, reopen it with portrait sessions create --resume <session-id> and use the ID that comes back.

Work with documents

Upload a file to My Library from the command line:

portrait files upload ./research-notes.pdf
portrait files upload ./model.xlsx --folder <folder-id>
portrait files upload ./memo.docx --project <project-id>

Upload takes one file at a time — one real file path, up to 25 MB. Directories, wildcards, and symbolic links are refused on purpose, so nothing is ever uploaded that you did not name explicitly.

A freshly uploaded document takes a moment to become readable. Check it, then read it back in chunks:

portrait files status <document-id>
portrait files read <document-id> --offset 0 --limit 65536

To ground a question in one specific document you already have in My Library:

portrait ask --document <document-id> "Summarize the key assumptions in this model."

Use it from an AI agent

The package includes a skill file that tells an AI coding agent how to drive the CLI — how to hold a session, when to ask for your approval, and where the boundaries are. Install it into your agent's skills directory:

portrait install-skill ~/.claude/skills

Add --force to replace an existing copy.

Two boundaries the skill enforces, and that are worth knowing yourself:

  • Confirmations come back to you. Creating a monitor or a screen consumes usage and shows up in your account, so when Easel asks for confirmation or a missing detail the agent must relay the question to you and send your answer on — never answer on your behalf. It must not poll a running screen or launch a second one.
  • Uploads need an exact path you confirmed. The agent must not scan a directory, expand a wildcard, or guess a file to send.

Output format

Every command writes a single JSON object to standard output, so results can be piped straight into other tools. portrait ask --stream is the one exception: it writes a stream of newline-delimited JSON records instead. Progress messages and sign-in instructions go to standard error, never mixed into the JSON.

Run portrait --help for the full command list.

For questions about access, contact the team.