Galya Docs
Galya (Beta)

Walkthrough

This is the whole Galya Beta in one sitting. You'll wire up a tiny retail catalog (a home-goods store), teach Galya one shopper's taste, and then query it.

The loop is always the same:

  1. Create a user: the person whose taste you're modeling.
  2. Index content linked to that user: the catalog items they like (entity_id does the linking).
  3. Compose: turn those linked items into the user's taste profile.
  4. Query: search, rerank, ask, explain, and list clusters.

What you need

A base URL of https://api.galya.io/v1 and a workspace secret key (galya_wsk_…) sent as the X-API-Key header. See Setup & auth for where to get the key. Set it once:

export GALYA_API_KEY="galya_wsk_…"

The #1 trap: query params, not body

search, rerank, ask, and explain need relative_to_entity_id and in_terms_of_entity_type in the URL query string — not the JSON body. Leave either out and you get:

{ "error": "relative_to_entity_id and in_terms_of_entity_type are required", "code": "bad_request" }

Every example below shows them in the URL. relative_to_entity_id is "whose taste," in_terms_of_entity_type is "what kind of thing to rank" (here, content).

Install the SDK (optional)

Every step shows curl and the @galya/agents TypeScript client. If you want the SDK:

npm install @galya/agents
import { GalyaApiClient } from "@galya/agents";

const api = new GalyaApiClient({ apiKey: process.env.GALYA_API_KEY! });

Run the whole thing

Save this as walkthrough.mts, then run it. It does every step above end to end.

npm install @galya/agents
npm install -D tsx            # if you don't have a TypeScript runner

export GALYA_API_KEY="galya_wsk_…"
npx tsx walkthrough.mts
Full runnable script (walkthrough.mts)
import { GalyaApiClient } from "@galya/agents";

const api = new GalyaApiClient({ apiKey: process.env.GALYA_API_KEY! });
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function main() {
  const userId = `shopper_jordan_${Date.now()}`;

  // 1. Create the user (the taste anchor). Returns HTTP 200.
  const user = await api.createEntity({
    id: userId,
    type: "user",
    name: "Jordan",
    description: "Likes calm, coastal, minimalist rooms — natural oak, linen, muted sand and white.",
  });
  console.log("user:", user.entity_id);

  // 2. Index catalog items LINKED to the user via entity_id.
  const catalog = [
    { url: `https://store.example/oak-credenza-${userId}`, content: "Low oak credenza, sand-toned linen front, soft coastal minimalist living room." },
    { url: `https://store.example/linen-sofa-${userId}`,   content: "Off-white linen slipcover sofa, airy bright room, natural materials, calm palette." },
    { url: `https://store.example/brass-lamp-${userId}`,   content: "Warm brass task lamp, muted neutral desk, understated minimalist workspace." },
  ];
  for (const item of catalog) {
    const r = await api.indexContent({
      content: { url: item.url, type: "text", content: item.content, skip_url_fetch: true },
      entity_id: user.entity_id,
    });
    console.log("indexed:", r.entity_id, "created:", r.created);
  }

  // Give link writes a moment to settle before composing.
  await sleep(5000);

  // 3. Compose the user's taste profile.
  const composed = await api.composeEntity(user.entity_id);
  console.log("composed:", composed.entity_id);

  // 4a. Search the catalog by taste (query params in the URL).
  const { results } = await api.search(
    { relativeToEntityId: user.entity_id, inTermsOfEntityType: "content" },
    { query: "calm coastal furniture in natural materials" },
  );
  console.log("search:", results.map((r) => r.id));

  // 4b. Rerank a shortlist (no history required).
  const reranked = await api.rerank(
    { relativeToEntityId: user.entity_id, inTermsOfEntityType: "content" },
    {
      candidates: [
        { url: `https://store.example/walnut-desk-${userId}`, type: "text", content: "Dark glossy walnut executive desk, ornate, maximalist." },
        { url: `https://store.example/linen-chair-${userId}`, type: "text", content: "Natural linen lounge chair, pale oak frame, airy minimalist." },
      ],
    },
  );
  console.log("rerank:", reranked.results.map((r) => r.id));

  // 4c. Ask a taste-personalized question.
  const askRes = (await api.ask(
    { relativeToEntityId: user.entity_id, inTermsOfEntityType: "content" },
    { query: "Recommend a sofa for my living room and say why it fits my taste." },
  )) as { answer: { content: { text: string }[] } };
  console.log("ask:", askRes.answer.content[0]?.text);

  // 4d. Explain the user's taste.
  const { explanation } = await api.explain(
    { relativeToEntityId: user.entity_id, inTermsOfEntityType: "content", domain: "design", task: "design-agent" },
    { query: "Summarize this shopper's furniture taste: palette, materials, silhouette." },
  );
  console.log("explain:", explanation);

  // 5. List taste clusters.
  const { results: clusters } = await api.listClusters({ entityType: "content", limit: 20 });
  console.log("clusters:", clusters.length);
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});

On this page