alva

>-

INSTALLATION
npx skills add https://github.com/alva-ai/skills --skill alva
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Alva

What is Alva

Alva is an agentic finance platform. It provides unified access to 250+

financial data sources spanning crypto, equities, ETFs, macroeconomic

indicators, on-chain analytics, and social sentiment -- including spot and

futures OHLCV, funding rates, company fundamentals, price targets, insider and

senator trades, earnings estimates, CPI, GDP, Treasury rates, exchange flows,

DeFi metrics, news feeds, social media and more!

What Alva Skills Enables

The Alva skill connects any AI agent or IDE to the full Alva platform. With it

you can:

  • Access financial data -- query any of Alva's 250+ data SDKs

programmatically, or bring your own data via HTTP API or direct upload.

  • Run cloud-side analytics -- write JavaScript that executes on Alva Cloud

in a secure runtime. No local compute, no dependencies, no infrastructure to

manage.

  • Build agentic playbooks -- create data pipelines, trading strategies, and

scheduled automations that run continuously on Alva Cloud.

  • Deploy trading strategies -- backtest with the Altra trading engine and

run continuous live paper trading.

  • Release and share -- turn your work into a hosted playbook web app at

https://alva.ai/u/<username>/playbooks/<playbook_name>, and share it with

the world.

  • Remix existing playbooks -- take any published playbook as a template,

read its feed scripts and HTML source, customize parameters/logic/UI, and

deploy as your own new playbook.

In short: turn your ideas into a forever-running finance agent that gets things

done for you.

Rule 0: alva --help is the source of truth

**Every time you're about to call an alva CLI command you have not used

in this session, run alva <command> --help first.** The help text is the

authoritative, always-up-to-date reference for every subcommand, flag,

response field, naming convention, and runnable example. Do not guess flag

names, parameter types, or response shapes from memory — the CLI surface

evolves, and stale assumptions silently break automations.

alva --help              # list all top-level commands

alva <command> --help    # full per-command surface (read this before calling)

The skill's references/api/*.md files exist only to record gotchas

the help text doesn't cover (synth-mount suffix corrections, playbook

README content shape, --signal schema, etc.). For everything else

— subcommand names, flag names, accepted values, response fields, examples

— treat alva <cmd> --help as canonical. If this doc and --help

disagree on a flag, trust --help and tell the user the doc needs an

update.

Pre-flight

Run these checks on first use each session before doing anything else.

1. Version Check

bash "<this skill's directory>/scripts/version_check.sh"
  • No output → up to date, proceed.
  • Output present → display to user, apply the update, then proceed.

2. Alva CLI Setup

The alva CLI (@alva-ai/toolkit) is the only way this skill interacts

with the Alva platform. It manages authentication, ships self-documenting

--help for every command (see [Rule 0](#rule-0-alva-command---help-is-the-source-of-truth)),

and eliminates the need for manual curl/header management.

Check whether the CLI is already installed by running alva --help.

-

If not installed, install it:

npm install -g @alva-ai/toolkit

-

If already installed, upgrade to the latest version to ensure access to

the newest commands and fixes:

npm install -g @alva-ai/toolkit@latest

Then check authentication (see step 2a below).

Third-party vendor secrets belong in Alva Secret Manager

(require("secret-manager")), not in the CLI config.

2a. Authentication Check

Run alva whoami. If it fails (no API key), run alva auth login to open

browser-based login, then re-run alva whoami to confirm.

3. User Profile

alva whoami
{"id":1, "username":"alice", "subscription_tier":"free", "active_channel":"discord", "telegram_username":"alice_tg", "discord_username":"alice"}

Session variables:

  • **username** — for public URLs and ALFS paths.
  • **subscription_tier** — "pro" or "free" (default). Determines release

flow (Step 7): pro can keep playbooks private.

  • **active_channel** — "telegram", "discord", or null. Web notifications

are always available; this controls external DM delivery.

  • **telegram_username / discord_username** — connected IM displays.

For external DM delivery, active_channel must point to a matching non-empty

display field.

4. Arrays JWT Check

Data skills require ARRAYS_JWT. The _meta.arrays_jwt field in the

alva whoami output above shows its status — if it needs attention (missing,

renewal_needed: true, or absent), use alva arrays token to manage it

(status to inspect, ensure to provision or refresh).

5. Load Memory

If you have not read the user's memory in this conversation, read it now.

alva fs read --path '~/memory/MEMORY.md'

If the file exists, read each file listed in the index (at minimum user.md).

If '~/memory/' does not exist or is empty, skip — it will be seeded on next

sign-in.

Use the loaded memory to tailor your responses to the user's profile,

preferences, and investment style. See the [Memory](#memory) section below for

reading and writing rules.

Communication

Vocabulary — use the terms in language.md exactly.

Default user-facing terms: automation (not "cronjob" or "feed"),

playbook, alert/notification, Agent, and script when discussing

code being built. Treat feed as an internal or diagnostic term: use it only

when the user is looking at logs, raw data, API fields, release references, or

an Automation detail that already exposes the term. Full definitions and

"avoid" labels are in that file.

No ALFS paths, API payloads, automation IDs, raw function names, internal jargon,

or implementation details in user-facing responses. Say what it DOES, not how it

works. These details are operating instructions for you, not content for the

user.

Lead with the result, not the process. The first thing the user reads should be

what they got ("Your dashboard is live at …"), not what you did ("I deployed

3 feeds and wrote the HTML"). During multi-step builds, give a short status

update at each milestone so the user knows work is progressing.

Data provenance in direct answers. When a direct answer cites specific

financial figures, each number must either come from a fresh SDK/BYOD fetch

(attributed inline to its source) or be explicitly qualified as an estimate

that the user should verify with current sources.

Request Routing

Request Type

Core Objectives

Dashboard / Playbook

Identify the needed data sources, validate the data flow, and produce a usable dashboard or playbook when the user wants a shareable artifact

Backtest / Strategy

Use Altra, run the backtest correctly, and always produce a visual playbook (equity curve, trade log, metrics) alongside the text summary. Optionally deploy as live paper trading.

Data Query

Fetch the requested data accurately and return it directly unless the user asks for a richer artifact

Remix

Reuse the source artifact, apply the requested changes, and return an updated result that matches the requested customization

Choose Skill (mandatory when /use-skill:/ is present)

If the user's message contains a /use-skill:<username>/<name> directive (e.g. /use-skill:alva/thesis, /use-skill:alice/btc-momentum), this step is mandatory and must run before Guided Planning and before any build work.

The directive gives the full catalog id (<username>/<name>). Skills are curated methodologies — opinionated blueprints that encode how to approach a recurring class of finance work (e.g. building a thesis, an AI-curated digest, a momentum tracker). They live in the Skillhub catalog on the gateway and are fetched via the alva skillhub CLI (use alva skillhub --help for the full surface). Alva ships a starter set under the alva/ namespace, and any user can publish their own — do not assume the alva/ namespace.

  • Inspect: alva skillhub get <username>/<name> returns the file listing with sizes. Confirm a blueprint file is present — convention is template.md. If absent, look for README.md or ask the user which file is the blueprint.
  • On 404 / not found (typo, deleted, or moved): run alva skillhub list and look for close matches leniently — case-insensitive, substring on both halves of the id, ignore separator differences. If exactly one obvious candidate, proceed with it and tell the user you corrected the id (e.g. "interpreting /use-skill:Alva/AI-Digest as alva/ai-digest"). If multiple plausible candidates, show them and ask. If nothing close, show the filtered list (use --tag if the user hinted at a topic) and ask the user to pick.
  • Read the blueprint: alva skillhub file <username>/<name> template.md (or the file from step 1). Do not proceed from memory of a prior session — fetch it fresh.
  • Pull other files on demand: when building, fetch additional files progressively as needed (e.g. alva skillhub file <username>/<name> src/index.js only if you intend to mirror the strategy logic). Do not bulk-download.
  • Treat the blueprint as authoritative for layout, sections, widgets, data contracts, and cadence. Deviate only where the user explicitly overrides it.
  • State the skill choice and any intentional deviations in your Guided Planning plan. The /use-skill: directive is a strong build directive — combined with a concrete topic, present the plan once and build; do not also stack clarifying multi-choice questions on top. Treat /use-skill: + concrete topic the same as "just do it": a single short plan, then build.

Content arrangement. A skill's default sections are a floor, not a ceiling. Lead with whatever carries the user's core question, proactively add sections the request demands, and cut or fold near-empty sections into neighbors rather than padding them.

Push-driven requests — if the user's primary outcome is a recurring push (digest, threshold tracker, stream watch, periodic alert), the alva/ai-digest skill is purpose-built for that shape and worth offering during Guided Planning. Push can also be added to any other playbook via Step 9 — the skill is one good option, not a requirement.

No /use-skill: directive → skip this step and proceed to Guided Planning normally.

Guided Planning

For all routes except Data Query, present a plan once before building.

Even seemingly clear requests ("build a BTC dashboard") have real choices —

which data, timeframe, widgets — that are cheaper to resolve upfront than to

rebuild.

Exactly one blocking question per session. Pick a single path through the

steps below — do not run step 1 clarifications AND a step 3 plan confirmation

in the same session. Whichever you use is the gate; the user's answer or

approval counts as approval to build, and you go directly to building

afterward.

  • Understand intent — When key parameters are missing (asset, scope,

output type, purpose) and have no obvious default, ask clarifying questions

one at a time, prefer multiple-choice. Skip this step if the request

already specifies these, or if the missing parameters have a single obvious

default. If you ran this step, do not also run step 3 — the answers

are the approval to build.

  • Propose approaches — Offer 2-3 concrete options with trade-offs when

there are real strategic alternatives. Lead with your recommendation. Skip

when the template or request already pins the approach.

  • Confirm the plan — When step 1 was skipped (request already clear, or

/use-skill: directive specifies the shape), present a single 5-8 line

plan listing the specific feeds and widgets, then build after approval.

State the skill (if any) and the key defaults you are using.

If the user says "just do it" at any point — or used /use-skill:<username>/<name>

together with a concrete topic — skip clarifying questions for the rest of the

session and present a single short plan, then build.

Completion Gate

For Dashboard/Playbook and Backtest/Strategy requests, the default goal

is to leave the user with a result they can actually use. In many cases that

means a released playbook and a published_url, but do not force that path if

the user only asked for code, analysis, debugging help, or an intermediate

artifact.

Before finishing, verify that the delivered result matches the user's actual

goal. When a shareable playbook was part of the task, verify:

  • A playbook was released and a published_url was returned

Must Do After Completion Gate:

  • Summarize the whole process and what is delivered to the user.

Capability Verification

Before saying "Alva doesn't have X" or recommending BYOD/third-party, run

alva data-skills list | grep -i <topic> first. Training memory is not

authoritative. Decompose compound requests ("darkpool L2 realtime") and

verify each component independently — never reject the whole as one unit.

Content Legitimacy Rules

These rules are non-negotiable. Violations produce misleading content that

displays fabricated data as if it were real. They apply to **every response

that surfaces financial values to the user** — playbook builds, dashboards,

query-mode answers, remixes, edits, and follow-ups — regardless of whether the

session ends with a released playbook.

Core principle: the agent's role is to build the pipeline, not to **be

the data source**. Any quantitative value the user sees must trace back to an

Alva SDK module, a published Alva feed, or a BYOD HTTP source that is either

user-provided or explicitly validated and wired into the feed pipeline. Agent

knowledge, LLM output, WebSearch snippets, random/synthetic generators, and

user-pasted snapshots are not legitimate data sources — regardless of

whether they appear as HTML literals, feed-script literals, backfilled

history, or agent-authored opinion columns. When the SDK has no coverage for

the requested domain, report the gap and stop; do not manufacture

plausible-looking data.

If the user's instruction conflicts with these rules — for example, asking

for synthesized/mock data, asking to skip the SDK and use local files only,

or asking for an artifact that would have to bypass the feed pipeline — ask

the user to resolve the conflict (use AskUserQuestion or text) before

proceeding. Do not silently substitute a different deliverable (local

prototype with seeded RNG, WebSearch summary, analytic memo without data

fetch) when the SDK can serve the original request.

Data Sourcing

-

**All quantitative data displayed in charts, tables, or metric cards MUST

originate from Alva feeds** (SDK modules or BYOD via require("net/http")).

Never hardcode data as inline JavaScript literals in playbook HTML.

-

Playbook HTML MUST fetch data at runtime from feed output paths.

Published HTML runs in the viewer's browser, so do not use sandbox-only env

vars such as $ALVA_ENDPOINT and do not guess https://api.alva.ai. Use the

public anonymous ALFS read gateway — see the readAlfsJson helper in

[Build the Playbook Web App](#6-build-the-playbook-web-app).

Static content (labels, colors, layout config) is fine. Quantitative data is

not — it must flow through the feed pipeline.

-

**Verification claims and quoted tool outputs must reflect actual tool

calls.** Do not describe a screenshot you did not take ("the dashboard

looks good"). When citing a tool-returned value such as published_url,

feed_id, or an ALFS path, copy it verbatim from the response. The

user-facing share link is the canonical

https://alva.ai/u/<username>/playbooks/<playbook_name> URL; published_url

is the deployed HTML URL used for verification steps such as screenshots.

Do not present one as if it were the other. If you need a value, re-read

the tool response first.

Prohibited Data Sources for Charts, Tables, and Query Answers

-

WebSearch / WebFetch results must NOT be embedded as data. Web search is

only legitimate for: reading documentation, finding API endpoints for BYOD,

understanding user requirements. It may help you discover a legitimate BYOD

source, but discovered values themselves must never be quoted as the answer

or injected as static data literals in feed scripts or playbook HTML. This

rule applies even when Alva API auth fails — in that case, report the

failure and stop; do NOT substitute a web-sourced value.

-

LLM / ADK output must NOT be presented as factual sourced data. ADK is

for reasoning, classification, summarization, and synthesis of real data — not

for generating numbers, statistics, events, or reports that claim to be from

real sources. If ADK produces quantitative output, it must be clearly labeled

as "AI-generated analysis".

-

Agent training knowledge must NOT fill data gaps. If an SDK does not have

the requested data type, report the gap as a blocker. Do not invent data from

your own knowledge to fill the hole.

Feed Scope Isolation

Do not reference other feeds or other playbooks' feeds. When building a

playbook, only read from feeds created for this playbook in the current

session.

Reference an existing feed only when the user explicitly asks for it (e.g.

"reuse my btc-ema feed", "pull data from @alice/macro-dashboard"). Otherwise,

build the playbook's own feeds from scratch so its data lineage is

self-contained and the playbook remains portable.

Qualitative analysis (ratings, theses, outlook text) is not data and must not

appear as feed output columns or "data" fields in HTML tables. If the user

asks for a rating, either compute it from SDK fundamentals with the formula

shown, or place it in a clearly labelled "AI analysis" section separated from

data-driven metrics.

SDK Coverage Gaps

-

When an SDK partition lacks the requested data type, reduce scope:

  • Omit the missing data section from the playbook and note the gap

(e.g. "ECB, BOJ, BOE rates — data source not yet available").

  • If the user has provided a specific data source URL, use BYOD

(require("net/http")) to fetch from it.

  • Do NOT hardcode point-in-time values in HTML — they become stale

immediately and violate content legitimacy rules.

  • Do NOT fabricate events or fill gaps from agent knowledge.

-

**When >20% of requested symbols fail SDK lookup, report a data-quality

blocker.** Do not silently substitute with estimated or fabricated values

marked live: false.

Release Gate: --feeds Is a Declaration, Not a Shortcut

alva release playbook --feeds '[]' is only valid when the released HTML

renders zero quantitative values at runtime (landing pages, UI-only demos).

If the HTML shows any numbers, charts, tables, or metric cards, the release

MUST reference deployed feeds in --feeds and the HTML MUST fetch() them

at runtime. If you used alva run to source data, deploy that same logic as

a feed and reference it.

Thematic Ticker Curation

When building sector or thematic dashboards with curated ticker lists:

  • Do NOT rely on agent knowledge for ticker-to-sector mapping.
  • After assembling the list, cross-check each ticker's sector using an SDK

call (e.g. getStockCompanyDetail) to verify it belongs to the intended

segment.

  • Remove mismatches before building the feed. A single wrong ticker (e.g. a

cybersecurity company in a battery segment) can distort the entire analysis.

Data Convention Alignment

A financial figure is not self-describing: what it means is fixed by

conventions the record encodes as fields — period basis (fiscal vs calendar),

price adjustment (split / dividend), currency, units, seasonal adjustment,

point-in-time vs restated. Before charting, tabulating, comparing, or

answering with any data series:

  • Read each convention from the record's own fields — never infer one from

your own knowledge of the company or market.

  • Every series in one chart, table, or comparison MUST share the same

conventions, and every label MUST state the convention it carries, derived

from the record rather than authored.

The fundamentals fiscal period is the case with the most depth: fiscal

quarters are not always calendar quarters (NVDA's fiscal year ends in late

January). Read fundamentals-periods.md

before charting or tabulating quarterly/annual fundamentals or computing

YoY/QoQ.

Description and Provenance Accuracy

-

**Playbook descriptions and methodology sections must only list data sources

that were actually called successfully.** Do not claim "Brave Search",

"ClinicalTrials.gov", or any other source unless the feed script actually

fetches from it at runtime.

-

Update frequency claims must match actual deployment. If cronjob

deployment failed, do not claim "updated every N hours" in the playbook

description. Either fix the cronjob or remove the claim.

Narrative Voice Rules

All user-facing prose the agent writes — playbook description and

display_name, hand-written HTML copy (hero text, intro cards, methodology

modal body, chart footnotes, rationale paragraphs), and any ADK system

prompts that produce narrative (TLDRs, digests, why-it-matters, delta

bodies, push-line headlines) — must follow

narrative-voice.md. Read that file before

writing or generating any user-facing prose.

The rules ban a specific list of AI-tell tokens and shapes (significance

inflation, negative parallelism, rule-of-three, generic closers, em-dash

overuse) and ship as a copy-paste system-prompt block with embedded

few-shots for ADK calls. Pure structured fields (numbers, tickers, dates,

enum labels, button labels) are exempt.

Capabilities &#x26; Common Workflows

1. ALFS (Alva FileSystem)

The foundation of the platform. ALFS is a cloud filesystem with per-user

isolation. Every user has a private home directory; all paths are private by

default and only accessible by the owning user. Public read access can be

explicitly granted on specific paths via grant. Scripts, data feeds, playbook

assets, and shared libraries all live on ALFS.

Key operations: read, write, mkdir, stat, readdir, remove, rename, copy,

symlink, chmod, grant, revoke.

In shell and documentation, wrap ALFS path arguments in single quotes (e.g.

'~/feeds/...', '/alva/home/...') so they are not confused with paths on your

local machine. See Filesystem.

2. JS Runtime

Run JavaScript on Alva Cloud in a sandboxed V8 isolate. Code executed via

alva run runs entirely on Alva's servers -- it cannot access

the host machine's filesystem, environment variables, or processes. The runtime

has access to ALFS, data skills via HTTP, runtime libraries, LLM access, and

the Feed SDK.

Absent globals — do not use:

  • process.* — no process object exists. For output use console.log

(not process.stdout.write); for env vars use

secret.loadPlaintext('NAME') (not process.env); to abort use

throw new Error(...) (not process.exit).

  • setTimeout / setInterval / clearTimeout — no timer globals.

Use a synchronous busy-wait helper or restructure to await-driven flow;

see references/snippets/sleep.md if it exists.

  • URLSearchParams — not in scope. Build query strings manually,

e.g. Object.entries(p).map(([k,v]) => k+'='+encodeURIComponent(v)).join('&#x26;'),

or use the helper your data skill exposes.

  • fetch (global) — must require('net/http') and use http.fetch.
  • Top-level await — wrap in (async () => { ... })().

If a script throws ReferenceError: <X> is not defined, the runtime

does not expose <X> — do not retry the same call; rewrite to one of

the patterns above.

3. Data Skills

Financial data APIs across 16+ domains, served by the Arrays backend

($ARRAYS_ENDPOINT, defaults to https://data-tools.prd.space.id). To find

the right API for a task, use the alva data-skills CLI (public, no auth).

Follow the pipeline in order; do not skip steps and do not guess inputs.

  • **alva data-skills list** — every skill id is namespaced arrays-data-api-*

and is not predictable from concept words, so always start here. Pipe

through grep to filter (e.g. alva data-skills list | grep -i stock).

  • **alva data-skills summary <skill>** — reveals the endpoint table.

<file> slugs come from its File column and are not guessable.

  • **alva data-skills endpoint <skill> <file>** — full parameters, response

fields, and examples. <file> is the File column value, not the Path.

  • Call Arrays data endpoints with Authorization: Bearer <ARRAYS_JWT>.

In runtime code, load the token via secret.loadPlaintext('ARRAYS_JWT').

The token is verified during preflight (see [Arrays JWT Check](#4-arrays-jwt-check));

if a call returns 401, re-run alva arrays token ensure. Do not use X-API-Key header.

#### Coverage Overview

Data skills span spot and derivatives markets across stocks, ETFs, options,

and crypto; equity fundamentals, estimates, events, and ownership flows;

on-chain metrics and exchange flows; macro and economic indicators; news;

and prediction markets. Run alva data-skills list for the live catalog.

Data skill doc lookup is mandatory. Always fetch the endpoint detail before

writing code that calls it. Do not guess paths, parameter names, or response

shapes from memory. The doc lookup ensures you use the correct endpoint and

handle the actual response format.

Enforcement: Before any Arrays data HTTP call or alva run that hits one,

you MUST have completed the full listsummaryendpoint pipeline for

that endpoint in this session. <skill> must come from list output and

<file> must come from the summary endpoints table — never from memory or

a guess. If the call fails with an unexpected shape, re-fetch the endpoint

detail rather than guessing.

Failure and fallback guardrail: If an Arrays endpoint returns 403, 404, or

an unexpected empty/irrelevant result, do not immediately tell the user to

upgrade or use BYOD. First re-check alva data-skills summary <skill> for the

same skill and look for a semantically equivalent endpoint; if <skill> itself

was guessed, re-run list to recover the correct id. Report BYOD as a final

fallback only after same-domain Alva endpoints cannot answer the question.

#### Runtime Libraries

Built-in modules that run inside the jagent V8 runtime via require(). These

are not data APIs — they are pure computation and utility libraries

available in every script execution.

Module group

Description

feed_widgets

Per-handle/channel rolling subscriptions — news, Twitter/X, YouTube, Reddit, podcasts (e.g. getTwitterFeed). Twitter also has historical backfill over a time window (getTwitterBackfill, Pro-gated). For topic/keyword search, use [Content Search](#content-search).

unified_search

Web, social, non-US finance search, and URL scraping tools (X/Grok, Perplexity Finance, Google, Brave, serper, decodo)

technical_indicator_calculation_helpers

50+ pure calculation helpers (RSI, MACD, Bollinger, etc.)

To discover available modules and their documentation:

  • alva sdk partitions — list all runtime module groups
  • alva sdk partition-summary --partition <name> — one-line summaries per group
  • alva sdk doc --name <module> — full doc for a specific runtime module

Pick a module group → partition-summary to see modules → sdk doc for full

documentation.

For unstructured content — news articles, social discussions, videos, podcasts

— see [Content Search](#content-search) below.

You can also bring your own data by uploading files to ALFS or fetching from

external HTTP APIs within the runtime.

#### Content Search

Search across Twitter/X, non-US finance data, news, Reddit, YouTube, podcasts, and general web.

Use whenever the playbook needs content beyond structured data SDKs — from

targeted queries ("what are people saying about NVDA earnings") to broad

discovery ("trending crypto discussions this week"), including social

discussions, finance search as the primary source for non-US equities and

the fallback for off-catalog asset classes (forex, traditional

index/commodity futures), market narratives, news coverage, sentiment,

analyst commentary, and community reactions. For US equities, crypto, and

deterministic time-series/fundamental data, prefer the structured Alva data

SDKs first.

Content search modules live in the unified_search runtime-library

partition. Discover them via the same partition API as the other runtime

libraries (GET /api/v1/sdk/partitions/unified_search/summary → module

listing; GET /api/v1/sdk/doc?name=... → full per-module documentation).

See search.md for per-source SDK usage,

enrichment patterns, and gotchas.

4. Altra (Alva Trading Engine)

A feed-based event-driven backtesting engine for quantitative trading

strategies. A trading strategy IS a feed: all output data (targets, portfolio,

orders, equity, metrics) lives under a single feed's ALFS path. Altra supports

historical backtesting and continuous live paper trading, with custom

indicators, portfolio simulation, and performance analytics.

5. Deploy on Alva Cloud

Once your data analytics scripts and feeds are ready, deploy them as scheduled

cronjobs on Alva Cloud. They run continuously on your chosen schedule (e.g.

every hour, every day). All data is private by default; grant public access to

specific paths so anyone -- or any playbook page -- can read the data.

User scope enforcement: All write, deploy, and release operations MUST

target only the requesting user's namespace. Before any fs/write,

draft/playbook, or release/playbook call, verify the target path and

username match the authenticated user (from alva whoami). If you have

access to multiple API keys (e.g. from prior sessions), identify the requesting

user and scope all operations to that user only. Do NOT write to or release

playbooks under other users' namespaces unless the request explicitly asks for

cross-user operations (e.g. remix with lineage).

Strategy / backtest / signal feeds require Altra: Any feed that produces

signal/targets or signal/alerts, or that performs backtesting, portfolio

simulation, equity-curve / drawdown / Sharpe computation, position tracking, or

rebalancing, MUST use FeedAltra — even for simple signal logic. Hand-rolled

for loops over price arrays, custom P&#x26;L accumulators, and direct

target-record building bypass bar alignment, portfolio simulation, and

look-ahead-bias prevention. See the

[Altra Trading Engine Quick Reference](#altra-trading-engine-quick-reference)

for the rationale.

Push notification streams: Subscriptions target feed/playbook resources,

not output paths. The output path only chooses the feed-alert source:

Output stream

Feed-alert source

Use for

Delivery eligibility

signal/targets

signal/targets

Playbook signals, trading targets, actionable alerts

Users or groups explicitly subscribed to the feed or to a playbook that references the feed

notify/message

notify/message

Feed results, AlvaAsk reports, heartbeat checks, proactive alerts

Users or groups explicitly subscribed to the feed or to a playbook that references the feed

Rules:

  • Both streams dispatch the canonical feed_alert_ready event. Do not use the

legacy names playbook_data_ready or feed_run_complete in new docs or

agent instructions.

  • A push-capable feed needs --push-notify and a feed release bound to the

cronjob:

alva deploy create --name <feed> --path '~/feeds/<feed>/v1/src/index.js' \

  --cron "<expr>" --push-notify

alva release feed --name <feed> --version 1.0.0 \

  --cronjob-id <ID_FROM_DEPLOY> --description "<one-sentence purpose>"
  • --push-notify only marks the feed publisher as capable of emitting alerts.

It does not subscribe any user or group, and it does not bypass

notification preferences.

  • Real delivery always requires an explicit subscription:

alva push-subscriptions subscribe-feed --username <owner> --name <feed>,

alva push-subscriptions subscribe-playbook --username <owner> --name <playbook>,

or a group /alva subscribe feed <id> / /alva subscribe playbook <id>.

Keep schema examples in feed-sdk.md Patterns D/E.

See Step 9 below for the post-release subscription flow.

6. Build the Playbook Web App

Required evidence:

  • The relevant companion reference has been read when applicable:

design-widgets.md for widget layouts,

design-components.md for component

details, and

design-playbook-trading-strategy.md

for strategy/backtest playbooks.

  • If a /use-skill: blueprint or template is active, its layout and data

contract have been read before HTML work starts.

If this evidence is missing, stop and read the required design/reference file

before creating or editing HTML. Do not rely on memory of prior sessions.

After your data pipelines are deployed and producing data, build the playbook's

web interface. Create HTML5 pages with Alva Design System that read from Alva's

data gateway and visualize the results. Follow the Alva Design System for

styling, layout, and component guidelines. Unless the user explicitly asks for a

static snapshot, default to a live playbook.

Data fetching requirement: Apply the

[Content Legitimacy Rules](#content-legitimacy-rules) when building the UI.

All quantitative data in charts, tables, or metric cards must come from feed

outputs read at runtime (no inline literals for data).

Use this browser-safe helper for published playbook HTML:

const PUBLIC_ALFS_READ_URL = "https://api-llm.prd.alva.ai/api/v1/fs/read?path=";

async function readAlfsJson(path) {

  const resp = await fetch(PUBLIC_ALFS_READ_URL + encodeURIComponent(path));

  if (!resp.ok) {

    throw new Error(`Failed to load ${path}: HTTP ${resp.status}`);

  }

  return resp.json();

}

$ALVA_ENDPOINT is available to sandbox scripts and CLI verification only. Do

not emit it into browser HTML; published HTML must call the public read gateway

above so anonymous viewers can load feed output without authentication.

7. Release

#### Common steps (all users)

-

Write HTML to ALFS: alva fs write --path '~/playbooks/{name}/index.html' --file ./index.html --mkdir-parents

-

Write README to ALFS (mandatory):

alva fs write --path '~/playbooks/{name}/README.md' --file ./README.md --mkdir-parents.

Every released playbook must ship a README at this exact path. See

Playbook README in release.md

for the canonical content shape (Overview, Data sources &#x26; freshness,

Blind spots, plus shape-specific sections for screener / thesis /

what-if). The README is the single source of truth for the playbook's

"How does this work?" surface — releasing without one leaves the

playbook unexplained.

-

Create playbook draft: alva release playbook-draft — creates DB

records, writes draft files and playbook.json to ALFS automatically.

If any item is missing, do not create the draft. Fix the missing artifact or

ask the user for the missing metadata first.

Run this before every alva release playbook to keep the draft

updated — including version bumps and re-releases.

This request must include both the URL-safe name and the human-readable

display_name. Use [subject/theme] [analysis angle/strategy logic], put

the subject/theme first, and keep it within 40 characters. Avoid personal

markers such as My, Test, or V2, and generic-only titles such as

Stock Dashboard or Trading Bot.

Trading symbols: If the playbook involves specific trading assets,

include "trading_symbols" in the request — an array of base asset

tickers (e.g. ["BTC", "ETH"], ["NVDA", "AAPL"]). The backend

resolves each symbol to a full trading pair object and stores the result

in the playbook metadata. Max 50 symbols per request. Unknown symbols

are silently skipped.

-

Screenshot: Take a screenshot to verify the released playbook renders

correctly from the deployed published URL (for example,

https://<username>.playbook.alva.ai/<playbook_name>/v1.0.0/index.html).

Always pass --compress (with --compress-quality / --compress-max-width

to shrink further) — PNG output is otherwise easily large enough to exceed

the 5 MB session upload cap:

alva screenshot --url <published_url> --out /tmp/screenshot.png \

  --compress --compress-quality 70 --compress-max-width 1280

The CLI handles authentication automatically. Run alva screenshot --help

for --selector and --xpath. Before reading the output, validate it is

actually a PNG — a failed capture may save a JSON error blob under the

.png name, and reading that into the session corrupts conversation

history:

head -c4 /tmp/screenshot.png | grep -q PNG || echo "SCREENSHOT_FAILED"

alva release playbook requires --readme-url, and it must be the

absolute ALFS path /alva/home/<username>/playbooks/<name>/README.md

(the relative <name>/README.md shorthand is no longer accepted).

Resolve <username> once via alva whoami. The flow is: first write

the README to ALFS, then pass the absolute path as --readme-url:

alva fs write --path '~/playbooks/{name}/README.md' --file ./README.md --mkdir-parents

alva release playbook ... --readme-url '/alva/home/<username>/playbooks/{name}/README.md'

Omitting the flag fails CLI argument parsing; passing any value other

than the absolute README path fails server validation with

InvalidArgument. See

release.md for full

validation rules and the canonical content shape.

#### Pro users ( subscription_tier = "pro" )

  • Show draft link: Output the playbook URL —

https://alva.ai/u/<username>/playbooks/<playbook_name>. The draft is

accessible only to the creator.

  • Ask: "Your playbook is ready. Would you like to publish it publicly, or

keep it private for now?"

  • Publish → call alva release playbook → output the public URL.
  • Keep private → done. Remind the user that only they can access the

draft URL.

#### Free users ( subscription_tier = "free" )

One-playbook cap. Free accounts may hold **at most one published

playbook**. The cap is enforced server-side at release time — a second

alva release playbook call will fail until the existing playbook is

deleted by the user.

-

Publish directly: Call alva release playbook — free playbooks

are always public. Output the public URL:

https://alva.ai/u/<username>/playbooks/<playbook_name>

-

**If the user already has a published playbook and wants to publish

a new one**, stop before calling alva release playbook. Tell the

user the existing playbook must be deleted first, and ask which path

they want:

  • Delete the old playbook — list their existing playbooks and

confirm which one to remove, then call the CLI directly:

alva playbook list                        # show what they have

alva playbook delete --name <old-name>    # soft-delete (frees the quota immediately)

Do not suggest alva fs remove --path ~/playbooks/<name>

that only clears ALFS files; the DB row stays and the quota stays

consumed. Do not attempt to "rename around" the cap, reuse the

old playbook's name without an explicit deletion, or assume any

in-app replace flow will migrate display_name, feeds, or

cronjobs cleanly — it currently does not, and the old public URL

can end up showing the new playbook's HTML with stale metadata.

  • Keep both — only possible on Pro. Offer the upgrade path at

https://alva.ai/pricing.

After the deletion call returns, re-run the full release pipeline

(draft → README → release) for the new playbook from scratch under

a fresh name.

-

Upsell only on friction: Do not proactively suggest upgrading.

But when the user's experience is degraded because of free-tier

limitations — wanting private playbooks, hitting the one-playbook cap,

resource limits, or any other pro-gated feature — acknowledge the

limitation and offer the upgrade path:

"This feature is available on the Pro plan. You can upgrade at

https://alva.ai/pricing to [specific benefit, e.g. keep playbooks

private / publish multiple playbooks / ...]."

Use the playbook name and the username from alva whoami to construct the

canonical share URL. Use published_url from the release response for

verification steps such as screenshots; do not present it as the share link.

#### Playbook Release Checklist

Required evidence:

  • Backing feed release gates passed: Every backing feed has passed

before-feed-release.

  • Deployment coverage: Every feed the released playbook reads at runtime

had a successful alva deploy create, and its feed_id appears in

--feeds. A run-tested but undeployed feed has no data at its public

@last path and the HTML will fail to read it.

  • Cronjobs are active: All feeds referenced by the playbook have

successfully deployed cronjobs.

  • HTML fetches from feeds: The playbook HTML reads quantitative data from

feed output paths at runtime, not from inline literals, consistent with the

[Content Legitimacy Rules](#content-legitimacy-rules).

  • Data is fresh: Read the latest data point from each referenced feed via

@last/1 and check its timestamp. If the latest timestamp is older than 2x

the cron interval, warn the user that the playbook will display stale data.

  • Description is accurate: Update frequency claims match actual cronjob

status. Data source claims match actual SDK/BYOD calls in the feed script.

  • Target user is correct: The playbook is being released under the

requesting user's namespace (see user scope enforcement above).

  • README is present and accurate: ~/playbooks/{name}/README.md exists

on ALFS and covers the required sections (see

Playbook README in release.md).

Its source / cadence claims match the actual feed scripts and deployed

cronjobs. Pass it via --readme-url as an absolute ALFS path (see the

--readme-url rule in Step 7 above).

  • Push feeds are released: Every cronjob this playbook deploys with

push_notify: true has a current alva release feed --cronjob-id <that cronjob> — run after the cronjob's latest source write and passing

before-feed-release; otherwise the push dispatches an empty body. Items

1–3 only check feeds the HTML reads; a push-only feed is not caught there.

If any item fails, do not release. Fix the issue, re-run

alva release playbook-draft if metadata or backing files changed, then

re-enter this gate.

8. Remix (Create from Existing Playbook)

Users can remix any published playbook to create a customized version. The Remix

prompt arrives as a <remix> tag — e.g.

<remix url="/u/alice/playbooks/btc-momentum" type="playbook" ...>...</remix>

— from which the agent extracts the source owner and name via the

url attribute. The agent then reads the source playbook's feed scripts

(strategy logic) and HTML (dashboard UI), customizes them per the user's

request, and deploys a new playbook under their own namespace. The tag's

inner text is a fixed instruction, not the user's customization request —

if the user typed nothing meaningful outside the tag, ask what to

customize before proceeding.

See remix-workflow.md for the full step-by-step

guide. alva remix commands are exclusively for lineage registration — to

read any playbook's files, use alva fs read.

9. Post-release push notification flow

After a playbook is released or kept as draft (Step 7 complete), proactively

evaluate whether any deployed feeds produce push-worthy content. Do not wait for

the user to ask.

#### Identify push-worthy feeds

Scan the feeds backing this playbook and classify each:

  • Push-worthy (recommend): price signals, crossover/breakout alerts,

trading instructions, anomaly detection, periodic research summaries —

anything actionable and time-sensitive.

  • Not push-worthy (skip): static fundamentals, historical snapshots,

low-frequency reference data.

If no feed qualifies, skip this flow entirely.

#### Check delivery channel

Web notifications are always available, so do not block push setup on Telegram

or Discord. For external DM delivery, read active_channel,

telegram_username, and discord_username from the session:

  • Active IM channel (active_channel is "telegram" with

telegram_username, or "discord" with discord_username) → proceed to

recommend the push.

  • No active IM channel → recommend the push, and tell the user:

"Web notifications will work immediately. To also receive this in Telegram or

Discord, connect and activate a channel at https://alva.ai/settings."

#### Recommend specific feeds

Present a concrete recommendation, not a generic "want push?":

"This playbook's BTC EMA crossover signal feed produces actionable

alerts when the trend flips. Want to enable push notifications for it?"

  • User says yes → configure end-to-end (see "Configure and verify" below).

Do not stop after toggling the flag.

  • User says no → accept and move on. Do not ask again.
  • User requests push for a different feed → honor their choice.

If the feed already has the right push sidecar for the intended event

(signal/targets for signal-style alerts, notify/message for feed

completion / AlvaAsk reports), push_notify: true, and a current

alva release feed, the publisher side is already configured. Still verify or

create the user's/group's explicit subscription before claiming notifications

are set up.

#### Configure and verify

A push is "set up" only after every step below succeeds. Stopping early is

the most common cause of "configured but nothing arrives" — do not skip

verification.

  • Add the intended push sidecar to the feed script:

signal/targets for playbook signals (Pattern D), or notify/message for

feed completion / AlvaAsk reports (Pattern E).

  • Release the feed. A push script is a feed: its push body is served from

the released feed, not the cronjob's raw run output. Run the changed

script through the [feed lifecycle](#deploying-feeds), before-feed-release

included.

  • Enable the flag on the cronjob: alva deploy update --id <ID> --push-notify.
  • Subscribe the delivery target: for personal push use

alva push-subscriptions subscribe-feed --username <owner> --name <feed>

or alva push-subscriptions subscribe-playbook --username <owner> --name <playbook>;

for group push, run /alva subscribe feed <id> or

/alva subscribe playbook <id> in that group.

  • Verify the release and a real run: confirm alva release feed --cronjob-id <this cronjob> ran after Step 1 added the sidecar. Then trigger

a run (or wait for the next cron fire) and read @last/1 of the configured

sidecar: confirm the record is fresh and the message body is non-empty.

  • Confirm to the user with the specifics: which feed/playbook is

subscribed, what the next push will say, and when it will fire.

If Step 5 finds the feed unreleased, or the run returns no record or an empty

body, do not claim push is set up — diagnose (missing release, missing

output write, wrong path, run failure) and fix before reporting success.

10. Annotation-driven edits

A request to tweak one element of a playbook in session context arrives as one

or more <annotation> tags, each naming a target element by CSS selector and

an instruction for it. Locate the generator behind the element — the CSS

rule or render function that produces it — and edit that. Never freeze the

element's rendered output into static text: that hardcodes live feed values and

breaks on the next data update.

See annotation-edits.md for the tag format and

the full locate-and-edit procedure.

Detailed sub-documents (read these for in-depth reference):

Document

Contents

references/api/*.md

Per-command gotchas the CLI help does not cover — see the [CLI Reference](#cli-reference) below

jagent-runtime.md

Writing jagent scripts: module system, built-in modules, async model, constraints

feed-sdk.md

Feed SDK guide: creating data feeds, time series, upstreams, state management

fundamentals-periods.md

Fiscal vs calendar periods for fundamentals: derive period labels from the record, align companies by calendarEndDate, compute YoY across matched periods

altra-trading.md

Altra backtesting engine: strategies, features, signals, testing, debugging

deployment.md

Deploying scripts as cronjobs for scheduled execution

design-system.md

Alva Design System entry point: tokens, typography, layout; links to widget, component, and playbook specs

remix-workflow.md

Remix: create a new playbook from an existing template

annotation-edits.md

Annotation-driven edits: parse <annotation> tags, locate the generator behind an element, edit generation logic not rendered output

creators-note.md

Post-release creator's note: composing and posting the pinned author comment

adk.md

Agent Development Kit: adk.agent() API, tool calling, ReAct loop, examples

search.md

Content search SDKs: per-source usage, enrichment patterns, and gotchas for Twitter/X, news, Reddit, YouTube, podcasts, and web

secret-manager.md

Secret upload, CRUD API, and runtime usage via require("secret-manager")

memory.md

Per-user memory: storage layout, user.md template, what to save, read/write rules

narrative-voice.md

Voice rules for user-facing prose: banned tokens/shapes, copy-paste ADK system-prompt block with few-shots

language.md

Canonical product vocabulary: automation, playbook, alert, Agent, and when feed must stay internal

CLI Reference

Per [Rule 0](#rule-0-alva-command---help-is-the-source-of-truth):

always run alva <command> --help before calling a command. The table is

a routing index — and, for the rows in bold, the linked sub-doc is a

mandatory read (the CLI help is wrong or silent on those surfaces).

Command

Purpose / must-read sub-doc

whoami / user

Authenticated identity, tier, IM channels, ALFS home.

fs

ALFS filesystem (read / write / readdir / grant / revoke / time series). Must read filesystem.md before any feed-data path, @… suffix, or fs grant on a feed — CLI help wrongly advertises @now, @range/{duration}, @all, @at, @range/@bounds.

run

Execute JS in the Alva V8 runtime.

deploy

Cronjob lifecycle (create / list / pause / resume / trigger / runs / run-logs).

release

Register feeds, draft and publish playbooks. Must read release.md before any playbook release — feed --description rules + the full README content shape (Overview / Data sources &#x26; freshness / Blind spots, plus screener / thesis / what-if).

secrets

CRUD on encrypted secrets read by require("secret-manager").

sdk

Runtime libraries (50+ technical indicators, search, widgets).

data-skills

Discover the 250+ Arrays financial-data endpoints.

skillhub

Pull curated methodology blueprints (/use-skill: flow).

comments

Create / pin / unpin playbook comments — see creators-note.md for the post-release creator's-note workflow.

push-subscriptions

Personal push opt-in for playbooks and feeds.

channel

Group push subscriptions (Telegram / Discord groups).

trading

Accounts, portfolio, orders, signals, risk. Must read trading.md before execute, building a signal JSON, or picking an exchange/symbol — real --signal schema is allocate/predict (not the {symbol,side,qty} shape the help example shows), date is epoch seconds.

screenshot

PNG capture used to verify a released playbook.

remix

Record parent-child lineage when remixing a playbook.

arrays

Provision / refresh the Arrays JWT (ARRAYS_JWT runtime secret).

auth / configure

Sign in, save API key + endpoint into a named profile.

Non-CLI references:

error-responses.md — HTTP status → error-code table for programmatic error handling.

Runtime Modules Quick Reference

Scripts executed via alva run run in a sandboxed V8 isolate on Alva's

servers -- they cannot access the host machine's filesystem, environment

variables, or shell. Host-agent permissions still apply. See

jagent-runtime.md for full details.

Module

require()

Description

alfs

require("alfs")

Filesystem (uses absolute paths '/alva/home/<username>/...')

env

require("env")

userId, username, args from request

secret-manager

require("secret-manager")

Read user-scoped third-party secrets stored in Alva Secret Manager

net/http

require("net/http")

fetch(url, init) for async HTTP requests

@alva/algorithm

require("@alva/algorithm")

Statistics

@alva/feed

require("@alva/feed")

Feed SDK for persistent data pipelines + FeedAltra trading engine

@alva/adk

require("@alva/adk")

Agent SDK for LLM requests — agent() for LLM agents with tool calling

@test/suite

require("@test/suite")

Jest-style test framework (describe, it, expect, runTests)

Runtime libraries: Built-in computation modules available via require()

(e.g. @alva/technical-indicators/rsi:v1.0.0). Version suffix is optional

(defaults to v1.0.0). To discover function signatures, use

alva sdk doc --name "...". Module groups: feed_widgets,

technical_indicator_calculation_helpers, unified_search.

Data APIs: Financial data (crypto, stock, macro, ETF) is fetched via HTTP

from the Arrays backend — see the [Data Skills](#3-data-skills) section. Load

ARRAYS_JWT via secret.loadPlaintext('ARRAYS_JWT') and call Arrays endpoints

with Authorization: Bearer <ARRAYS_JWT>.

Secret Manager: use const secret = require("secret-manager"); then

secret.loadPlaintext("OPENAI_API_KEY"). This returns a string when present or

null when the current user has not uploaded that secret.

Key constraints: Module exports are frozen. For absent globals — no

top-level await, no process, no Node.js builtins — see

[JS Runtime](#2-js-runtime).

Feed SDK Quick Reference

See feed-sdk.md for full details.

Feeds are persistent data pipelines that store time series data, readable via

filesystem paths.

Feed error handling is fail-fast. Do not wrap feed data fetches, upstream

feed reads, LLM parsing, or ctx.self.ts().append() calls in catch blocks

that log and continue with empty arrays, nulls, fallback records, or partial

outputs. Let unexpected failures throw; the sandbox captures thrown errors and

exposes the failed run. Use normal conditionals only for expected business

states such as "no new records since the last watermark."

**Throw with a meaningful message; don't let undefined.x be the error.**

When a precondition might fail (empty fetch result, all rows filtered out,

misaligned bars across symbols), check it and throw new Error("X empty: Y").

A cryptic TypeError: Cannot read properties of undefined is fail-fast in

name only — operators can't act on it.

// ❌  TypeError: Cannot read properties of undefined (reading 'equity')

const finalEq = equityRecords[equityRecords.length - 1].equity;

// ✅  Names what's missing.

if (!equityRecords.length) throw new Error("equityRecords empty: no aligned bars across " + TICKERS);

const finalEq = equityRecords[equityRecords.length - 1].equity;

For a complete worked feed (schema, incremental ctx.kv watermark, time-series

append) and the output read path, see the Quick Start in

feed-sdk.md.

Data Modeling Patterns

All data produced by a feed should use feed.def() + ctx.self.ts().append().

Do not use alfs.writeFile() for feed output data.

Pattern A -- Snapshot (latest-wins): For data that represents current state

(company detail, ratings, price target consensus). Use start-of-day as the date

so re-runs overwrite.

const today = new Date();

today.setHours(0, 0, 0, 0);

await ctx.self

  .ts("info", "company")

  .append([

    { date: today.getTime(), name: company.name, sector: company.sector },

  ]);

Read @last/1 for current snapshot, @last/30 for 30-day history.

Pattern B -- Event log: For timestamped events (insider trades, news,

senator trades). Each event uses its natural date. Same-date records are

auto-grouped.

const records = trades.map((t) => ({

  date: new Date(t.transactionDate).getTime(),

  name: t.name,

  type: t.type,

  shares: t.shares,

}));

await ctx.self.ts("activity", "insiderTrades").append(records);

Pattern C -- Tabular (versioned batch): For data where the whole set

refreshes each run (top holders, EPS estimates). Stamp all records with the same

run timestamp; same-date grouping stores them as a batch.

const now = Date.now();

const records = holdings.map((h, i) => ({

  date: now,

  rank: i + 1,

  name: h.name,

  marketValue: h.value,

}));

await ctx.self.ts("research", "institutions").append(records);

Data Type

Pattern

Date Strategy

Read Query

OHLCV, indicators

Time series (standard)

Bar timestamp

@last/252

Company detail, ratings

Snapshot (A)

Start of day

@last/1

Insider trades, news

Event log (B)

Event timestamp

@last/50

Holdings, estimates

Tabular (C)

Run timestamp

@last/N

See feed-sdk.md for detailed data modeling examples

and deduplication behavior.

Deploying Feeds

Every feed follows a 6-step lifecycle including every newly created feed or re-created feed:

-

Write -- define schema + incremental logic with ctx.kv

-

Upload — write script to '~/feeds/<name>/v1/src/index.js'

-

Testalva run --entry-path '~/feeds/<name>/v1/src/index.js' to verify output.

For SDK modules you haven't used before in this session, first run a

shape-check snippet to verify response structure:

const r = await mod.someFunction({ symbol: "AAPL" });

console.log(JSON.stringify(r).slice(0, 500));

Verify the actual response nesting (e.g. {success, response: {rates:[]}}

vs flat array) matches your feed script's parsing logic before proceeding.

alva run is a test step — it does NOT write to the production @last

path. Never skip alva deploy below on the assumption that the run

"already produced the data".

The run must succeed before moving on. If alva run throws, returns

an error, produces empty output when records were expected, or surfaces

a response shape that doesn't match the script's parsing, stop and fix

the feed script. Do not proceed to Grant / Deploy / Release on a failed

or empty run — a broken feed that is granted and deployed will publish

nothing (or stale data) and fail the release checklists later.

-

Grant -- make feed data publicly readable:

alva fs grant --path '~/feeds/<name>' --subject "special:user:*" --permission read

Grant on the feed root path (not on data/). Subject format:

special:user:* (public), special:user:+ (authenticated only), user:<id>

(specific user).

-

Deploy -- alva deploy create for scheduled execution

-

Release -- alva release feed to register the feed in the

database (requires the cronjob_id from the deploy step)

Feed Release Checklist

Required evidence:

  • Run check: alva run --entry-path '~/feeds/<name>/v1/src/index.js'

completed successfully after the latest source write.

  • Output shape check: The run produced the expected feed output

groups/fields for this feed.

  • Freshness check: If the script changed after the run, the evidence is

stale. Re-run before release.

  • Grant check: special:user:* read permission exists on the feed path.

If missing, run the grant step now.

  • Public-read check: Fetch the feed data path without authentication and

confirm HTTP 200, not 403.

  • HTML backing check: If the feed backs HTML, at least one public @last

path that the HTML will read has a non-empty result after grant.

If this evidence is missing or stale, do not run alva release feed. Re-run

the feed, inspect the output, and only then proceed.

Building a playbook? Every backing feed still passes this gate first;

then, before alva release playbook, pass before-playbook-release in Step 7

— it covers HTML, README, freshness, and feed coverage.

If the build was interrupted and resumed, re-enter this gate from the top.

Do not assume prior steps completed successfully.

Data Type

Recommended Schedule

Rationale

Stock OHLCV + technicals

0 */4 * * * (every 4h)

Markets update during trading hours

Company detail, price targets

0 8 * * * (daily 8am)

Changes infrequently

Insider/senator trades

0 8 * * * (daily 8am)

SEC filings are daily

Earnings estimates

0 8 * * * (daily 8am)

Updated periodically

See deployment.md for the full deployment guide and

API reference.

Error Transparency

When SDK modules fail or are unavailable, you MUST be transparent with the user.

Do not silently fall back to inferior data sources.

Pro / Subscription-Gated SDKs

When an SDK module returns a Pro-only or subscription error:

  • Inform the user which module is unavailable and why (subscription tier).
  • Assess scope impact — determine whether the gated module is the sole

data source for the playbook, or one of several.

  • Partial dependency (other free-tier modules can still power most of

the playbook): proceed with a reduced-scope build. Omit the gated

section and note it in the playbook (e.g. "Congressional trading data

requires Pro — section omitted"). Deliver what you can.

  • Full dependency (the entire playbook hinges on this module): tell

the user specifically: "This data requires a Pro subscription. You can

upgrade, or provide a custom data source URL and I'll wire it up via

BYOD." Do NOT leave an open-ended question; give exactly these two

actionable options.

  • Never stop with zero output. If you can build any useful subset of

the requested playbook with free-tier modules, do so.

  • Never silently substitute with LLM-fabricated data.

Coverage Limitations

Some asset classes — e.g. forex pairs and traditional index/commodity

futures — sit outside Alva's structured Data Skills catalog. State that

upfront rather than discovering it through failed searches, then fall back to

searchPerplexityFinance (see search.md); suggest

BYOD only if that also falls short and a public API exists.

Debugging Feeds

Resetting Feed Data (development only)

During development, use the CLI to clear stale or incorrect data. **Do not use

this in production.**

# Clear a specific time series output

alva fs remove --path '~/feeds/my-feed/v1/data/market/ohlcv' --recursive

# Clear an entire group (all outputs under "market")

alva fs remove --path '~/feeds/my-feed/v1/data/market' --recursive

# Full reset: clear ALL data + KV state (removes the data mount, re-created on next run)

alva fs remove --path '~/feeds/my-feed/v1/data' --recursive

Inline Debug Snippets

Test data skill response shapes before building a full feed:

alva run --code '(async()=>{const http=require("net/http");const secret=require("secret-manager");const jwt=secret.loadPlaintext("ARRAYS_JWT");const r=await http.fetch("https://data-tools.prd.space.id/api/v1/crypto/ohlcv?symbol=BTCUSDT&#x26;start_time=1735689600&#x26;end_time=1735776000&#x26;interval=1h&#x26;limit=5",{headers:{Authorization:"Bearer "+jwt}});console.log(JSON.stringify(JSON.parse(await r.text()).data[0]));})();'

Memory

Alva gives every user a persistent, file-based memory system on ALFS at

'~/memory/'. Use it to accumulate knowledge about the user across

conversations — identity, preferences, investment style, and context useful in

future sessions.

'~/memory/MEMORY.md' is the index; topic files such as user.md hold the

content and are read on demand. Memory files are user-visible and editable

— write them as if the user will read them. Memory is a claim, not truth: it

records what was true when written, so verify any feed, cronjob, or parameter

it names before acting on it.

Read MEMORY.md at the start of every conversation — this is wired into

[Pre-flight](#5-load-memory). See memory.md for the

storage layout, the user.md profile template, what to save and what not, and

the full read/write rules.

Secret Manager

Use Alva Secret Manager whenever a playbook or runtime script needs a

third-party credential such as an LLM API key, search token, exchange key, or

webhook secret.

  • Preferred upload path: ask the user to add or edit the secret in the web

UI at https://alva.ai/apikey. Assume this page is available.

  • Do not ask the user to paste sensitive third-party secrets into chat when

the web upload flow is feasible.

  • Do not hardcode secrets in source code, ALFS files, .env, shell

snippets, or released playbook assets.

  • Runtime access: load secrets inside Alva Cloud code with

require("secret-manager").loadPlaintext("NAME").

  • loadPlaintext(name) returns the plaintext string when present, or null

when the secret is missing for the current user.

  • If a required secret is missing, stop and tell the user exactly which secret

name to upload at https://alva.ai/apikey.

  • For agent-managed setup, inspection, or cleanup, authenticated CRUD endpoints

are available via alva secrets.

Read secret-manager.md whenever the task

involves uploading, naming, rotating, listing, or using third-party secrets.

Altra Trading Engine Quick Reference

Always use Altra for backtesting. Altra handles bar.endTime timestamps,

data alignment, and portfolio simulation automatically. Do not manually loop

over SDK data (e.g. getCryptoKline) to evaluate trading conditions — this

leads to incorrect timestamps and look-ahead bias. Use Altra for all

strategies regardless of complexity; external data can be added via

registerRawData. For OHLCV, use only intervals supported

by createArraysOhlcvProvider() (see altra-trading.md): stocks support

"1min", "2min", "3min", "5min", "10min", "15min", "30min",

"1h", "2h", "4h", "1d", "1w", "1m"; crypto supports those plus

"45min" and locally aggregated minute/hour/day multiples such as "6h" or

"3d".

Stock intraday window guardrail: Do not directly request multi-year US

stock intraday ("1min"/"5min"/"15min"/"30min"/hourly) backtests as one

full window. The underlying Arrays/data-tools endpoint rejects large intraday

windows (for example >~366 days for "1min"). If the user asks for 2 years of

intraday stock data, explain the limit and either narrow the backtest window,

use daily/weekly bars when appropriate, or use a provider path that explicitly

chunks the request.

**After a successful backtest, you should package the results in a form the user

can use.** That may be a playbook, a dashboard, or a concise analytical summary,

depending on the request. A backtest that only prints raw console output is

usually incomplete — see

[Request Routing](#request-routing) above.

See altra-trading.md for full details.

const { FeedAltraModule, createArraysOhlcvProvider } = require("@alva/feed");

const { FeedAltra, e, Amount } = FeedAltraModule;

const secret = require("secret-manager");

const ARRAYS_JWT = secret.loadPlaintext("ARRAYS_JWT");

const ohlcvProvider = createArraysOhlcvProvider({ jwt: ARRAYS_JWT });

const altra = new FeedAltra(

  {

    path: "~/feeds/my-strategy/v1",

    startDate: Date.parse("2025-01-01T00:00:00Z"),

    portfolioOptions: { initialCash: 1_000_000 },

    simOptions: { simTick: "1min", feeRate: 0.001 },

    perfOptions: { timezone: "UTC", marketType: "crypto" },

  },

  ohlcvProvider,

);

const dg = altra.getDataGraph();

dg.registerOhlcv("BINANCE_SPOT_BTC_USDT", "1d"); // supported interval strings include "1min", "15min", "1d"

dg.registerFeature(createRsiFeature()); // feature descriptors include description, inputConfig, fields, and fn

altra.setStrategy(strategyFn, {

  trigger: { type: "events", expr: e.ohlcv("BINANCE_SPOT_BTC_USDT", "1d") },

  inputConfig: {

    ohlcvs: [{ id: { pair: "BINANCE_SPOT_BTC_USDT", interval: "1d" } }],

    features: [{ id: "rsi" }],

  },

  initialState: {},

});

(async () => {

  await altra.run(Date.now());

})();

ADK (Agent Development Kit) Quick Reference

@alva/adk (adk.agent()) embeds a fixed LLM reasoning step inside a

deterministic, reschedulable pipeline — a feed cronjob's summarization stage,

a scheduled digest, a "why it matters" headline, a classification step. The

prompt and tool set are locked in; only the upstream data changes each run.

Do not use it for one-off research, exploratory analysis, or "help me look

into X" the user asks interactively — answer directly with your own tools;

wrapping it in adk.agent() adds a sandbox without buying anything. And do

not use it to produce numbers, events, or reports that should come from a real

data source (see Content Legitimacy Rule #2 above).

See adk.md for the API, tool-calling and memory patterns,

and examples.

Deployment Quick Reference

See deployment.md for full details.

Deploy feed scripts or tasks as cronjobs for scheduled execution:

alva deploy create --name btc-ema-update --path '~/feeds/btc-ema/v1/src/index.js' --cron "0 */4 * * *"

Cronjobs execute the script via the same jagent runtime as alva run. Min

interval: 1 minute.

Name format: All resource names (cronjobs, feeds, playbooks) must be 1–63

lowercase alphanumeric characters or hyphens, and cannot start or end with a

hyphen (DNS label format). Example: btc-ema-update, not BTC EMA Update.

After deploying a cronjob, register the feed, create a playbook draft, then

release the playbook for public hosting. The playbook HTML must already be

written to ALFS at '~/playbooks/{name}/index.html' via fs/write before

releasing.

Important: Feed names and playbook names must be unique within your user

space. Before creating a new feed or playbook, use

alva fs readdir --path '~/feeds' or

alva fs readdir --path '~/playbooks' to check for existing names and avoid

conflicts.

# 1. Release feed (register in DB, link to cronjob)

alva release feed --name btc-ema --version 1.0.0 --cronjob-id 42 \

  --description "Fetches BTC/USDT 1h klines from Binance and emits the 20-period EMA as a time series"

# → {"feed_id":100,"name":"btc-ema","feed_major":1}

# 2. Create playbook draft (creates DB record + ALFS draft files automatically)

#    Include trading_symbols when the playbook involves specific assets.

#    Include --tags with discovery tags (max 10, each up to 32 chars) so the

#    playbook surfaces under those tags on /explore. Re-running this command

#    with --tags replaces the playbook's tag set.

alva release playbook-draft --name btc-dashboard --display-name "BTC Trend Dashboard" --description "BTC market dashboard" --feeds '[{"feed_id":100}]' --trading-symbols '["BTC"]' --tags '["btc","macro"]'

# → {"playbook_id":99,"playbook_version_id":200}

# 3. Write playbook README to ALFS (required before release).

alva fs write --path '~/playbooks/btc-dashboard/README.md' --file ./README.md --mkdir-parents

# 4. Release playbook (reads HTML from ALFS, uploads to CDN, writes release files automatically).

#    --readme-url is required and must be the absolute ALFS path to the README

#    written above (the relative shorthand is no longer accepted).

alva release playbook --name btc-dashboard --version v1.0.0 --feeds '[{"feed_id":100}]' --changelog "Initial release" --readme-url '/alva/home/alice/playbooks/btc-dashboard/README.md'

# → {"playbook_id":99,"version":"v1.0.0","published_url":"https://alice.playbook.alva.ai/btc-dashboard/v1.0.0/index.html"}

# After release, output the canonical share link to the user:

# https://alva.ai/u/<username>/playbooks/<playbook_name>

# e.g. https://alva.ai/u/alice/playbooks/btc-dashboard

Alva Design System

Always read design-system.md first — it covers tokens,

typography, theme, and page-level layout. Then read only the spec you need:

  • Generating a widget or chart

design-widgets.md

  • Using a component (Button, Tag, Dropdown, Tab, etc.) →

design-components.md

  • Building a trading strategy playbook

design-playbook-trading-strategy.md

  • Only need global rules → stay in design-system.md

Filesystem Layout Convention

Path (ALFS — quote in CLI)

Purpose

'~/tasks/<name>/src/'

Task source code

'~/feeds/<name>/v1/src/'

Feed script source code

'~/feeds/<name>/v1/data/'

Feed synth mount (auto-created by Feed SDK)

'~/playbooks/<name>/'

Playbook web app assets

'~/data/'

General data storage

'~/library/'

Shared code modules

Prefer using the Feed SDK for all data organization, including point-in-time

snapshots. Store snapshots as single-record time series rather than raw JSON

files via alfs.writeFile(). This keeps all data queryable through a single

consistent read pattern (@last, @range, etc.).

Common Pitfalls

  • **@last returns chronological (oldest-first) order**, consistent with

@first and @range. No manual sorting needed.

  • Time series reads return flat JSON records. Paths with @last, @range,

etc. return JSON arrays of flat records like

[{"date":...,"close":...,"ema10":...}]. Regular paths return file content

with Content-Type: application/octet-stream.

  • **last(N) limits unique timestamps, not records.** When multiple records

share a timestamp (grouped via append()), auto-flatten may return more than

N individual records.

  • **The data/ in feed paths is the synth mount.** feedPath("my-feed") gives

'~/feeds/my-feed/v1', and the Feed SDK mounts storage at <feedPath>/data/.

Don't name your group "data" or you'll get data/data/....

  • Public reads require absolute paths. Unauthenticated reads must use

'/alva/home/<username>/...' (not '~/...'). Discover your username via

alva whoami.

  • **Top-level await is not supported.** Wrap async code in

(async () => { ... })();.

  • **require("alfs") uses absolute paths.** Inside the V8 runtime,

alfs.readFile() needs full paths like '/alva/home/alice/...'. Get your

username from require("env").username.

  • No Node.js builtins. require("fs"), require("path"), require("http")

do not exist. Use require("alfs") for files, require("net/http") for HTTP.

  • **Altra run() is async.** FeedAltra.run() returns a Promise<RunResult>.

Always await it: const result = await altra.run(endDate);

  • Altra lookback: feature vs strategy. Feature lookback controls how many

historical records feature computation receives. Strategy lookback controls

the OHLCV, raw, and feature records delivered to the strategy, and can extend

upstream raw/feature computation ranges so requested records are available.

  • **Quote ~ paths to prevent shell expansion.** The shell expands bare ~ to

your local home (e.g. /Users/alice/), not the ALFS home

('/alva/home/alice/'). Always quote paths: --path '~/feeds/...'.

  • Home directory not provisioned? If you get PERMISSION_DENIED on all

ALFS operations (including '~/'), your home directory was not created during

sign-up. Call alva fs mkdir --path '~/' to provision it. This is idempotent

and safe to call anytime.

  • Cronjob path must point to an existing script. The deploy API validates

the entry_path exists via filesystem stat before creating the cronjob.

  • Create new playbooks from scratch unless you are doing a version update.

Only version updates may refer to an existing playbook. For all other new

playbooks, do not read existing ones.

  • **ECharts: use type: 'time' for date axes.** Do not pass raw epoch

millisecond values as category labels — users will see numbers like

1773840600000 instead of dates. Use type: 'time' axis, which handles

formatting automatically, or format dates before passing to a category axis.

  • ECharts graph: validate node/edge data. For type: 'graph' series with

layout: 'none', verify every edge source/target matches an existing

node name, no duplicate node names exist, and node names don't contain

special characters that break ECharts internals. Add a try/catch wrapper

around chart initialization with a fallback message if rendering fails.

  • ECharts sizing: allocate sufficient height. Heatmaps need

height = max(300px, numRows * 40px). Primary charts on overview tabs should

be at least 400px tall and visually dominant over metric cards. Do not compress

charts to fit everything above the fold.

  • **Separate lastDate watermarks per data source.** When a feed combines

multiple data sources with different update frequencies (e.g. ETF OHLCV +

VIX + CPI), use a separate ctx.kv key for each source's watermark (e.g.

lastDate_etf, lastDate_vix, lastDate_cpi). A shared watermark causes

slower-updating sources to be permanently filtered out after the first run.

Resource Limits

Resource

Limit

V8 heap per execution

2 GB

Write payload

10 MB max per request

HTTP response body

128 MB max

Min cron interval

1 minute

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card