# Generate a prisebe JSON file with an AI agent

This guide explains how an AI agent can turn a user's manually provided asset information into a JSON file that prisebe can visualize.

The machine-oriented reusable instructions are maintained in [`skills/prisebe-json-generator/SKILL.md`](../skills/prisebe-json-generator/SKILL.md). After a static deployment, the same skill is available at `/skills/prisebe-json-generator/SKILL.md`.

The generated file is a local, portable workspace. The user can open it from the Welcome page with **Open existing file**, inspect the data in the UI, make corrections, and download the updated file for the next iteration.

## Important rules for the AI agent

- Generate JSON only. Do not add Markdown fences, comments, explanations, or extra top-level properties to the file.
- Use `schemaVersion: 1.2`. Files with `schemaVersion: 1` are migrated automatically when opened.
- Use ISO 8601 date-time strings for `updatedAt`, `asOf`, and `updatedAt` on value entries.
- Store monetary amounts and rates as strings, not numbers. For example, use `"12500.00"`, not `12500`.
- Use stable, unique 8-character alphanumeric IDs. Do not encode names or URLs in IDs; generate compact values such as `a7K2mPq9` and reuse them for relationships.
- Every `resource.portfolioId` must match an existing portfolio ID.
- Every ID in `resource.tagIds` must match an existing tag ID.
- Every `valueEntry.resourceId` must match an existing resource ID.
- Use only `active` or `archived` for `status`.
- For an archived resource, include `archivedAt` as the ISO 8601 date-time when it was archived. Active resources should omit `archivedAt`.
- Do not add fields such as `assetCategory`, `owner`, `monthlyPrice`, or `price`. Classification belongs in generic reusable `tags`, and values are recorded as dated value entries.
- Do not invent historical values, exchange rates, or dates. If the user did not provide them, leave the relevant collection empty or ask for clarification.
- A value entry is append-only history. Do not overwrite an older entry just because a newer value is available.

## Required top-level shape

```json
{
  "schemaVersion": 1.2,
  "updatedAt": "2026-09-09T12:00:00Z",
  "baseCurrency": "USD",
  "portfolios": [],
  "resources": [],
  "tags": [],
  "valueEntries": []
}
```

All top-level collections are required, even when they are empty. Do not add a top-level `currencies` list; the app derives available currencies from `baseCurrency` and `resources[].currency`.

## Entity fields

### Portfolio

```json
{
  "id": "a7K2mPq9",
  "name": "My assets",
  "status": "active"
}
```

Use one portfolio for a normal first file. Multiple portfolios are supported by the schema, but each resource must belong to exactly one of them.

### Resource

```json
{
  "id": "n4X8bR2c",
  "portfolioId": "a7K2mPq9",
  "name": "Savings account",
  "currency": "EUR",
  "tagIds": ["t9Lm3Qw1", "z6Hk8Vd4"],
  "description": "Long-term savings account",
  "status": "active"
}
```

A resource is a place where value is held. Its `currency` is the currency used for its value entries. If one account contains balances in different currencies, represent each currency as a separate resource.
`description` is an optional persistent note about the resource.
When a resource is archived, set `status` to `archived` and add `archivedAt`, for example: `"archivedAt": "2026-09-15T14:30:00Z"`. Preserve all value entries; archiving does not delete history. Do not add `archivedAt` to active resources.

### Tag

```json
{
  "id": "t9Lm3Qw1",
  "name": "Shared",
  "status": "active"
}
```

Tags are generic labels. They may describe a person, purpose, asset type, location, or any other grouping the user wants. Reuse the same tag ID instead of creating duplicate tags with the same meaning.

### Value entry

```json
{
  "id": "v2Qa7Ns5",
  "resourceId": "n4X8bR2c",
  "asOf": "2026-09-09T09:00:00Z",
  "amount": "12500.00",
  "updatedAt": "2026-09-09T09:00:00Z",
  "description": "Added after the September transfer"
}
```

The UI resolves the exchange rate through Frankfurter when it needs a reporting value. Do not include converted values or rate metadata in the file. `description` is an optional point-in-time note shown in the resource's description timeline.

## Copy-ready prompt for an AI agent

The following prompt can be given to an AI agent together with the user's wealth notes:

```text
Convert the user's asset notes into a prisebe JSON file.

Return JSON only, without Markdown fences or commentary. The file must use schemaVersion 1.2 and exactly these top-level sections:
schemaVersion, updatedAt, baseCurrency, portfolios, resources, tags, valueEntries.

Rules:
- Use ISO 8601 date-time strings for timestamps.
- Store all monetary amounts as decimal strings.
- Create unique 8-character alphanumeric IDs and preserve all relationships by ID. Never put names, URLs, or dates into IDs.
- Every resource must reference an existing portfolio and every tagId must reference an existing tag.
- Every value entry must reference an existing resource.
- Use generic tags only; do not create assetCategory, owner, monthlyPrice, or price fields.
- Do not invent missing values, dates, ownership, or tags.
- Do not create a separate exchange-rate collection. Use the Frankfurter API at runtime when the UI submits a value.
- If a required fact is missing, ask a concise clarification question instead of guessing.
- Keep historical value entries; add a new entry for each distinct dated observation.
- Keep each value entry in the resource's original currency. The UI obtains reporting conversions from Frankfurter at runtime.
- Before returning the JSON, check that all IDs are unique, all references resolve, and every top-level collection is present.

User's wealth notes:
[paste notes here]
```

## Complete example

```json
{
  "schemaVersion": 1.2,
  "updatedAt": "2026-09-09T12:00:00Z",
  "baseCurrency": "USD",
  "portfolios": [
    {
      "id": "a7K2mPq9",
      "name": "My assets",
      "status": "active"
    }
  ],
  "resources": [
    {
      "id": "c3Fd8Lm2",
      "portfolioId": "a7K2mPq9",
      "name": "Cash reserve",
      "currency": "USD",
      "tagIds": ["t9Lm3Qw1", "p5Jr6Ks8"],
      "description": "Emergency cash reserve",
      "status": "active"
    },
    {
      "id": "n4X8bR2c",
      "portfolioId": "a7K2mPq9",
      "name": "Savings account",
      "currency": "EUR",
      "tagIds": ["t9Lm3Qw1", "z6Hk8Vd4"],
      "description": "Long-term savings account",
      "status": "active"
    }
  ],
  "tags": [
    {
      "id": "t9Lm3Qw1",
      "name": "Shared",
      "status": "active"
    },
    {
      "id": "p5Jr6Ks8",
      "name": "Cash",
      "status": "active"
    },
    {
      "id": "z6Hk8Vd4",
      "name": "Deposits",
      "status": "active"
    }
  ],
  "valueEntries": [
    {
      "id": "q1Wm4Er7",
      "resourceId": "c3Fd8Lm2",
      "asOf": "2026-09-09T09:00:00Z",
      "amount": "2500.00",
      "updatedAt": "2026-09-09T09:00:00Z",
      "description": "Initial balance"
    },
    {
      "id": "v2Qa7Ns5",
      "resourceId": "n4X8bR2c",
      "asOf": "2026-09-09T09:00:00Z",
      "amount": "12500.00",
      "updatedAt": "2026-09-09T09:00:00Z",
      "description": "Added after the September transfer"
    }
  ]
}
```

## Before opening the file

The AI agent or user should perform these checks:

1. Parse the content as JSON.
2. Confirm there are no comments, trailing commas, or Markdown fences.
3. Confirm all IDs are unique.
4. Confirm all references resolve.
5. Confirm the file has no top-level `currencies` field; resource currencies are stored on each resource.
6. Save the result with a `.json` extension, then open it in the app using **Open existing file**.

If the app rejects the file, use the validation message shown on the Welcome page, correct the JSON, and try again. The application does not upload the file to a backend.
