VeyraDocumentation
npm install

Core

Planning + focus

useveyra

Memory

Semantic context

useveyra/memory

Voice

Realtime sessions

useveyra/voice

Solana

Identity + proofs

useveyra/solana
Privacy first: Veyra uses Solana for identity, payments, rewards, and achievements—not for private tasks, journals, or personal memory.

useveyra

enter image description here

A memory-aware AI planning, focus, progress, and achievement SDK for TypeScript.

useveyra turns unstructured thoughts into bounded plans, retrieves relevant personal context, tracks focus sessions without background timers, summarizes actual outcomes, and supports optional voice and Solana integrations. Its dependency-injected architecture works offline, with OpenAI, or with application-owned providers and persistence adapters.

Contents

Why Veyra

Most productivity APIs model a task as a row in a database. Veyra models a larger loop: capture an ambiguous thought, recall useful preferences, build a realistic plan, execute it in focus sessions, record outcomes, and turn those outcomes into gentle summaries or optional rewards.


flowchart LR

A["Unstructured thought"] --> B["Validate input"]

B --> C["Retrieve relevant memories"]

C --> D["Planning provider"]

D --> E["Validated bounded plan"]

E --> F["Focus session"]

F --> G["Progress summary"]

G --> H["Quest and achievement evaluation"]

H -. "reusable learning" .-> C

The core productivity model remains offchain. Solana is restricted to wallet identity, payments, achievement identifiers, and public proof hashes.

Feature matrix

| Capability | Offline | OpenAI | Browser-safe | Persistent by default |

| ------------------------------------ | :--------------------: | :----------: | :------------------------: | :-------------------: |

| Deterministic planning | Yes | — | Yes | No |

| Structured AI planning | — | Yes | Backend only | No |

| Semantic memory retrieval | With a custom provider | Yes | Backend only | No |

| Focus sessions | Yes | Optional | Yes | No |

| Statistical summaries | Yes | Not required | Yes | No |

| Quests, XP, and streaks | Yes | Not required | Yes | No |

| Realtime voice session configuration | — | Yes | Secret consumed in browser | No |

| Solana unsigned transactions | Yes | — | Wallet signs externally | No |

In-memory stores are deliberately process-local. Production applications should inject encrypted persistent adapters.

Requirements and installation


npm  i  useveyra

  • Node.js 20 or newer

  • TypeScript is recommended for the complete API contract

  • A server-side OpenAI API key for OpenAI planning, embeddings, or voice configuration

  • An explicit OpenAI planning model; the SDK does not assume model availability

  • An application-selected RPC endpoint and mint for Solana payments

The package publishes ESM, CommonJS, TypeScript declarations, declaration maps, and JavaScript source maps.

Quick starts

OpenAI planning

import {
  InMemoryMemoryStore,
  InMemoryProgressStore,
  OpenAIEmbeddingProvider,
  OpenAIPlanningProvider,
  Veyra,
} from "useveyra";

const apiKey = process.env.OPENAI_API_KEY;

const model = process.env.VEYRA_OPENAI_MODEL;

if (!apiKey || !model) {
  throw new Error("Set OPENAI_API_KEY and VEYRA_OPENAI_MODEL");
}

const veyra = new Veyra({
  planningProvider: new OpenAIPlanningProvider(apiKey, model),

  embeddingProvider: new OpenAIEmbeddingProvider(
    apiKey,

    process.env.VEYRA_EMBEDDING_MODEL,
  ),

  memoryStore: new InMemoryMemoryStore(),

  progressStore: new InMemoryProgressStore(),
});

const plan = await veyra.plans.create({
  userId: "user_123",

  thought:
    "I need to finish the landing page, answer emails, and prepare tomorrow's launch.",

  availableMinutes: 120,

  energy: "medium",

  maximumTasks: 4,

  timezone: "Asia/Makassar",
});

console.log(plan.summary, plan.tasks, plan.influencedByMemories);

Fully offline planning

import {
  DeterministicPlanningProvider,
  FixedClock,
  InMemoryMemoryStore,
  InMemoryProgressStore,
  Veyra,
} from "useveyra";

const clock = new FixedClock("2026-01-01T09:00:00.000Z");

let sequence = 0;

const nextId = () => `demo_${++sequence}`;

const veyra = new Veyra({
  planningProvider: new DeterministicPlanningProvider(clock, nextId),

  memoryStore: new InMemoryMemoryStore(),

  progressStore: new InMemoryProgressStore(),

  clock,

  idGenerator: nextId,
});

const plan = await veyra.plans.create({
  userId: "offline_user",

  thought: "Draft the launch post, review it, schedule it",

  availableMinutes: 75,
});

Run the repository example without credentials or network access:


npm  run  example:offline

System architecture

The Veyra facade coordinates domain behavior. Providers own model calls, stores own persistence, and injected clocks/ID generators make time-dependent behavior reproducible.


flowchart TB

subgraph Application["Application boundary"]

API["Veyra facade"]

Browser["Browser client"]

Wallet["Wallet adapter"]

end



subgraph Core["Core SDK"]

Plans["Planning service"]

Memory["Memory and ranking"]

Sessions["Session state machine"]

Progress["Summaries and rewards"]

end



subgraph Adapters["Injected adapters"]

PlanningProvider["PlanningProvider"]

EmbeddingProvider["EmbeddingProvider"]

MemoryStore["MemoryStore"]

ProgressStore["ProgressStore"]

Clock["Clock and ID generator"]

end



subgraph Optional["Optional subpath exports"]

Voice["OpenAI Realtime"]

Solana["Solana identity, proof, payment"]

end



API --> Plans

API --> Memory

API --> Sessions

API --> Progress

Plans --> PlanningProvider

Memory --> EmbeddingProvider

Memory --> MemoryStore

Sessions --> ProgressStore

Sessions --> Clock

Browser --> Voice

Wallet --> Solana

Planning request sequence


sequenceDiagram

participant App

participant V as Veyra

participant E as EmbeddingProvider

participant M as MemoryStore

participant P as PlanningProvider

participant S as ProgressStore



App->>V: plans.create(input, options)

V->>V: Zod validation

opt Embeddings configured

V->>E: embed(thought)

E-->>V: query vector

V->>M: list(userId)

M-->>V: candidate memories

V->>V: similarity + importance + recency + novelty

end

V->>P: createPlan(input + memory content)

P-->>V: structured Plan

V->>V: validate time bound

V->>S: savePlan(plan)

V-->>App: typed Plan

Configuration

Veyra accepts explicit dependencies:

| Property | Required | Purpose |

| ------------------- | :------: | -------------------------------------------- |

| planningProvider | Yes | Produces typed plans |

| memoryStore | Yes | Stores and retrieves personal memories |

| progressStore | Yes | Stores plans and focus sessions |

| embeddingProvider | No | Enables semantic memory ranking |

| clock | No | Controls time; defaults to SystemClock |

| idGenerator | No | Creates entity identifiers |

| xpPerTask | No | Configures non-negative XP per verified task |

Supported environment variables are documented in .env.example:


OPENAI_API_KEY=

VEYRA_OPENAI_MODEL=

VEYRA_EMBEDDING_MODEL=text-embedding-3-small

VEYRA_OPENAI_TIMEOUT_MS=30000

VEYRA_REALTIME_MODEL=

SOLANA_RPC_URL=https://api.devnet.solana.com

SOLANA_CLUSTER=devnet

Environment variables are application configuration; the SDK constructors receive explicit values and do not silently read process state.

Plans

Create a plan with veyra.plans.create(input, options?).

const plan = await veyra.plans.create(
  {
    userId: "user_123",

    thought: "Review analytics and write the weekly update",

    availableMinutes: 50,

    energy: "low",

    maximumTasks: 3,

    currentTime: new Date().toISOString(),

    timezone: "Europe/Amsterdam",
  },

  { timeoutMs: 30_000, signal: abortController.signal },
);

Plan.tasks contain an ID, title, optional description, duration, energy, priority, reason, and lifecycle status. Veyra rejects a provider result whose total duration exceeds availableMinutes. influencedByMemories contains usable memory content, not vector values or private ranking metadata.

Memory

Save, search, update, and forget

const preference = await veyra.memory.remember({
  userId: "user_123",

  kind: "preference",

  content: "I prefer writing work before meetings.",

  importance: 0.8,
});

const matches = await veyra.memory.search({
  userId: "user_123",

  query: "When should I schedule writing?",

  limit: 5,

  kinds: ["preference", "habit"],
});

await veyra.memory.update({ id: preference.id, importance: 0.9 });

await veyra.memory.forget({ id: preference.id });

Memory kinds are goal, habit, preference, blocker, and reflection. Importance is normalized to 0..1.

Ranking model

When embeddings are configured, candidate memories are ranked locally:


score = similarity × 0.55

+ importance × 0.25

+ recency × 0.15

+ novelty × 0.05

| Component | Weight | Interpretation |

| ---------- | -----: | ------------------------------------------------- |

| Similarity | 55% | Cosine relevance between query and memory vectors |

| Importance | 25% | Application/user-assigned long-term value |

| Recency | 15% | Preference for recently updated information |

| Novelty | 5% | Mild preference for memories not used recently |

All components and the final score are bounded to 0..1.

Extraction modes

const result = await veyra.memory.extract({
  userId: "user_123",

  text: "I prefer quiet rooms. The weather is nice today.",

  confirmationMode: "suggest",
});
  • automatic: persist reusable candidates immediately.

  • suggest: return candidates without persistence.

  • explicit: return candidates for an application-controlled confirmation flow.

Focus sessions


stateDiagram-v2

[*] --> Active: start

Active --> Paused: pause

Paused --> Active: resume

Active --> Completed: complete

Paused --> Completed: complete

Active --> Cancelled: cancel

Paused --> Cancelled: cancel

Completed --> [*]

Cancelled --> [*]

const session = await veyra.sessions.start({
  userId: "user_123",

  planId: plan.id,

  taskId: plan.tasks[0]?.id,

  plannedMinutes: 25,
});

await veyra.sessions.checkIn({
  sessionId: session.id,

  note: "First draft complete",

  progress: 0.6,

  interrupted: false,
});

await veyra.sessions.pause(session.id);

await veyra.sessions.resume(session.id);

const completed = await veyra.sessions.complete({ sessionId: session.id });

No permanent timer runs. Active elapsed time is derived from stored timestamps and the injected clock. Invalid transitions throw SessionStateError.

Summaries

const daily = await veyra.summaries.daily({
  userId: "user_123",

  date: "2026-08-04",

  timezone: "Asia/Makassar",
});

const weekly = await veyra.summaries.weekly({
  userId: "user_123",

  start: "2026-08-03T00:00:00.000Z",

  timezone: "Asia/Makassar",
});

Summaries report period boundaries, completed task/session counts, completed minutes, highlights, patterns, gentle suggestions, and a narrative based on recorded outcomes.

Quests, XP, and streaks

const quest = await veyra.quests.fromPlan({ planId: plan.id });

await veyra.quests.completeTask({
  questId: quest.id,

  taskId: plan.tasks[0]!.id,

  verified: true,

  idempotencyKey: `completion:${quest.id}:${plan.tasks[0]!.id}`,
});

const progress = veyra.quests.getProgress({ questId: quest.id });

const streak = await veyra.streaks.get({
  userId: "user_123",

  timezone: "Asia/Makassar",
});

XP is awarded only for verified task completion. Reusing an idempotency key or rewarding the same task twice raises DuplicateRewardError. Streak calendar dates are calculated in the supplied IANA timezone.

Achievements

Built-ins include First Focus, Deep Work, Seven Day Rhythm, Quest Complete, and Consistent Explorer.

const eligible = await veyra.achievements.evaluate({ userId: "user_123" });

const unlocked = await veyra.achievements.unlock({
  achievementId: eligible[0]!.id,
});

const proof = await veyra.achievements.createProof({
  achievementId: unlocked.id,

  wallet: "A_VALID_SOLANA_WALLET_ADDRESS",

  evidenceHash: "64_HEXADECIMAL_CHARACTERS",
});

Evaluation is deterministic and separate from blockchain transaction construction.

Voice

Voice is isolated behind useveyra/voice. The standard OpenAI key remains on a trusted server.


sequenceDiagram

participant Browser

participant Backend

participant OpenAI



Browser->>Backend: Request voice session

Backend->>OpenAI: Create ephemeral client secret

OpenAI-->>Backend: Short-lived secret

Backend-->>Browser: VoiceSessionConfig

Browser->>OpenAI: Connect with ephemeral secret

Server:

import { OpenAIVoiceProvider } from "useveyra/voice";

const voice = new OpenAIVoiceProvider(
  process.env.OPENAI_API_KEY!,

  process.env.VEYRA_REALTIME_MODEL,
);

const config = await voice.createSessionConfig({
  instructions: "Be concise, calm, and task-focused.",
});

Browser-safe consumption:

import { consumeVoiceSessionConfig } from "useveyra/voice";

const config = consumeVoiceSessionConfig(await response.json());

Voice events cover transcript deltas, assistant audio, interruption, error, and session completion.

Solana

Wallet identity

import { InMemoryNonceStore } from "useveyra";

import { SolanaIdentityService } from "useveyra/solana";

const identity = new SolanaIdentityService(new InMemoryNonceStore());

const challenge = await identity.createChallenge({
  domain: "app.example.com",

  wallet: walletAddress,

  expiresInSeconds: 300,
});

const result = await identity.verifyChallenge({
  message: challenge.message,

  wallet: walletAddress,

  nonce: challenge.nonce,

  signature: base58Signature,
});

Challenges bind domain, wallet, nonce, issued time, and expiration. Nonces are single-use and signatures are Ed25519-verified. The SDK never asks for a private key.

Achievement proof

import { SolanaAchievementService } from "useveyra/solana";

const service = new SolanaAchievementService();

const payload = service.createProofPayload({
  wallet: walletAddress,

  achievementId: "first-focus",

  earnedAt: Math.floor(Date.now() / 1000),

  version: 1,

  evidenceHash: sha256Hex,
});

const transaction = service.buildProofTransaction({
  proof: payload,

  programId,
});

The returned transaction is unsigned and unbroadcast. Private task names, conversation text, habits, blockers, and memory content are never fields in AchievementProof.

USDC transfer

import { SolanaPaymentService } from "useveyra/solana";

const payments = new SolanaPaymentService();

const transaction = await payments.buildUsdcTransfer({
  cluster: "devnet",

  rpcUrl: "https://api.devnet.solana.com",

  mint: configuredMint,

  sender: senderWallet,

  recipient: recipientWallet,

  amount: "12.50",

  decimals: 6,
});

Currency arrives as a decimal string and is converted to integer base units with BigInt; floating-point currency arithmetic is not used. Applications must select the correct mint for their cluster.

Custom adapters

import type {
  Plan,
  PlanningProvider,
  PlanningProviderInput,
  RequestOptions,
} from "useveyra";

class RulesPlanningProvider implements PlanningProvider {
  async createPlan(
    input: PlanningProviderInput,

    _options?: RequestOptions,
  ): Promise<Plan> {
    const createdAt = input.currentTime ?? new Date().toISOString();

    return {
      id: crypto.randomUUID(),

      userId: input.userId,

      summary: "One deliberately small next step.",

      tasks: [
        {
          id: crypto.randomUUID(),

          title: input.thought,

          durationMinutes: Math.min(input.availableMinutes ?? 25, 25),

          energy: input.energy ?? "medium",

          priority: "medium",

          reason: "Keep the first action concrete and bounded.",

          status: "pending",
        },
      ],

      totalDurationMinutes: Math.min(input.availableMinutes ?? 25, 25),

      checkInAfterMinutes: 15,

      createdAt,
    };
  }
}

Custom MemoryStore and ProgressStore implementations can use PostgreSQL, DynamoDB, SQLite, or another application-controlled system without modifying Veyra.

Errors and request control

All SDK errors extend VeyraError and expose code, message, retryable, optional cause, and optional safe metadata.

| Error | Typical meaning |

| ------------------------ | --------------------------------------------- |

| ConfigurationError | Missing or invalid SDK/provider configuration |

| ValidationError | Invalid request or invalid provider result |

| AuthenticationError | Provider or wallet authentication failed |

| ProviderError | External provider failed |

| RateLimitError | Retryable provider throttling |

| TimeoutError | Request timed out or was aborted |

| MemoryStoreError | Memory persistence failed |

| ProgressStoreError | Progress persistence failed |

| SessionStateError | Invalid focus-session transition |

| DuplicateRewardError | Duplicate XP award attempt |

| SolanaTransactionError | Solana validation or construction failed |

| VoiceSessionError | Ephemeral voice configuration failed |

import { VeyraError } from "useveyra";

const controller = new AbortController();

try {
  const plan = await veyra.plans.create(input, {
    signal: controller.signal,

    timeoutMs: 30_000,

    idempotencyKey: "plan:user_123:2026-08-04",
  });
} catch (error) {
  if (error instanceof VeyraError) {
    console.error({ code: error.code, retryable: error.retryable });
  }
}

Retryable provider errors use bounded exponential backoff with jitter. Validation and authentication failures are not retried. Provider response bodies, tokens, and private memories are excluded from public error messages.

Privacy and threat boundaries


flowchart LR

Private["Private offchain data\nTasks, memories, habits, blockers"]

Backend["Trusted application backend"]

OpenAI["Configured AI provider"]

Public["Public Solana data\nWallet, achievement ID, time, version, hash"]

Browser["Browser"]



Private --> Backend

Backend -->|"selected planning context"| OpenAI

Backend -->|"ephemeral secret only"| Browser

Backend -->|"unsigned proof payload"| Public

Private -. "never serialized" .-> Public

  • Keep standard OpenAI keys on trusted servers.

  • Browser applications should call their own backend.

  • Never pass wallet private keys or seed phrases into Veyra.

  • Veyra builds unsigned Solana transactions; the wallet retains approval control.

  • Productivity data remains offchain.

  • Achievement proofs contain identifiers, timestamps, versions, wallet addresses, and hashes only.

  • Deleting an in-memory memory removes the complete record, including its embedding.

  • Avoid logging authentication tokens, provider keys, voice secrets, or memory content.

  • Encrypt production stores at rest and apply per-user authorization in the adapter layer.

Package exports

| Import | Contents | Intended environment |

| ----------------- | ----------------------------------------------------------- | --------------------------------------------------------------------- |

| useveyra | Core client, types, stores, utilities, providers, errors | Node.js/server; deterministic pieces also work in compatible runtimes |

| useveyra/server | Veyra and OpenAI providers | Trusted server |

| useveyra/memory | Memory store, scoring, and memory contracts | Server or application adapter layer |

| useveyra/voice | Realtime provider, voice contracts, browser config consumer | Server and browser split |

| useveyra/solana | Identity, achievement proof, and payment services | Server or wallet-enabled application |

Every export provides import, require, and declaration targets. The package declares sideEffects: false for tree shaking.

Development and publishing


npm  install

npm  run  format:check

npm  run  lint

npm  run  typecheck

npm  run  test

npm  run  test:coverage

npm  run  build

npm  run  example:offline

npm  pack  --dry-run

Additional commands:

| Command | Purpose |

| ------------------------ | -------------------------------- |

| npm run dev | Watch the tsup build |

| npm run test:watch | Run Vitest interactively |

| npm run format | Apply Prettier formatting |

| npm run clean | Remove build and coverage output |

| npm run prepublishOnly | Run the configured release gate |

Before publishing, inspect the dry-run tarball, confirm no .env file or secret is present, and verify both ESM and CommonJS consumers.


npm  login

npm  publish  --access  public

Versions follow semantic versioning: patches fix compatible behavior, minors add compatible APIs, and majors may contain breaking contract changes.

License

MIT. See LICENSE.