Skip to content
Agentmart
Submit a tool

arkiv-data-modeling

Design typed Arkiv entity models for application queries, PostgreSQL mappings, marketplace schemas and relationships.

Skill by Arkiv-Network

IndexedMIT★ 1
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/arkiv-network-arkiv-data-modeling

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Design typed Arkiv entity models for application queries, PostgreSQL mappings, marketplace schemas and relationships. Use when choosing attributes versus payload, exact numeric encodings, application IDs, entity-key references or consistency rules. Use arkiv-social-graph to read or visualize relationships with arkiv-graph. Importing rows and executing writes require their own authorization.

Use cases: design, data

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/arkiv-data-modeling

What's inside

Skill name
arkiv-data-modeling
Description
Design typed Arkiv entity models for application queries, PostgreSQL mappings, marketplace schemas and relationships. Use when choosing attributes versus payload, exact numeric encodings, application IDs, entity-key references or consistency rules. Use arkiv-social-graph to read or visualize relationships with arkiv-graph. Importing rows and executing writes require their own authorization.
License
MIT
Metadata
network: tiramisu · verified: 2026-10-08 · arkiv-sdk: >=0.8.1 <0.9
Instructions
175 lines in SKILL.md · view on GitHub

Files (3)

  • SKILL.md
  • postgres-to-entity.md · references/
  • relationships.md · references/

SKILL.md (first lines)

# Model data for the queries you need

## When to use

Use this skill before implementing an Arkiv entity schema. Start with the requested screen or operation: which entity type it returns, filters, ranges, sort, expected cardinality, trusted creators and update policy.

For an existing error, use arkiv-troubleshooting first. Use arkiv-query for pagination, arkiv-entity-lifecycle for mutation permissions, and arkiv-security-trust for authorization. Use arkiv-write-safety to journal and reconcile multi-step writes, arkiv-entity-expiration for related deadlines, and arkiv-first-write for a first transaction.

Check the installed SDK version and declarations. Examples below target SDK 0.8.1 on Tiramisu. Without that local evidence, explain the model and documented operations conceptually and ask for the missing declarations; do not assemble executable code from guessed imports. Producing a model does not authorize publishing data or spending GLM.

## Storage rules

- Put scalar fields needed by predicates in **attributes**. Put nested objects, arrays, long descriptions and other unqueried data in **payload**. Both are public; exclude secrets and private fields before encoding either.
- Specify an Entity Expiration policy for every entity type, including in a conceptual model: an explicit lifetime supplied through `expires: ExpirationTime.fromDays(...)`, or an absolute block deadline through `ExpirationTime.atBlock(...)`. Ask for the retention requirement when it is missing; do not invent a duration. A relationship's deadline must also follow the chosen endpoint policy; saying only that it must not outlive its targets leaves the targets' own expiration unspecified.
- Create permits 32 cells total. Payload and content type consume two, leaving **30 user attributes**, including namespace and schema fields. Patches also count system mutations against their operation budget. Separately, Tiramisu caps the resulting entity at **32 user attributes** after a patch; splitting transactions cannot grow beyond that state ceiling.
- Use lowercase `snake_case` application names, at most 32 bytes, beginning with a letter; exclude reserved query words and type tags listed in [limits](../arkiv/references/limits.md). The SDK accepts a wider alphabet than the current node; this conservative convention avoids the uppercase node rejection. `project` plus `entity_type` scopes an application's data. Anyone can copy these values; scope trusted reads by creator too.
- A `str` holds at most 128 UTF-8 bytes and excludes C0 controls and DEL. Validate a text limit from the input contract; never silently truncate or replace a requested text filter with a hash.
- There are nine user attribute types. `bytes` is system-only payload storage, not a tenth user type. No indexed array, object or null constructor exists.

| Constructor | Representation and use | Bare default |
| --- | --- | --- |
| `bool(true)` | Boolean | `true` / `false` |
| `i32(10)` | Signed 32-bit integer | JavaScript `number` |
| `u64(1700000000000n)` | Unsigned 64-bit integer; app milliseconds and blocks | None |
| `u256(1250n)` | Unsigned 256-bit integer; exact minor currency/token units | JavaScript `bigint` |
| `dec('12.50')` | Signed fixed-point, 18 decimal places; canonical decimal string | None |
| ``bytes32(`0x${'ab'.repeat(32)}`)`` | Exactly 32 opaque bytes | None |
| `str('listing_42')` | UTF-8 text | JavaScript `string` |
| `addr('0x1111111111111111111111111111111111111111')` | Address | None |
| ``key(`0x${'12'.repeat(32)}`)`` | Entity reference; dangling targets are allowed | None |

Use the same constructor when writing and querying: `price_minor: u256(1250n)` pairs with `eq('price_minor', u256(1250n))`. Bare `1250` is `i32`; bare `1250n` is `u256`. A timestamp from `Date.now()` needs `u64(...)`; a bare timestamp is rejected as an out-of-range `i32`.

For exact money, choose a documented currency and scale. Store nonnegative minor units with `u256`, or signed decimal amounts with `dec` using a decimal string. Fractional JavaScript numbers are rejected by `dec`; excess decimal precision is rejected, not rounded. Decide rounding in the application's numeric layer.

`dec` preserves the numeric value, not its input formatting; `addr` returns a checksummed address. Keep exact source strings in payload when needed, declare any display scale, and compare addresses case-insensitively.

Omit a nullable attribute when absent; an update to null must unset the old attribute. Preserve `0`, `false` and `''`. Infer absence only from a complete attribute projection. JSON payload can retain explicit null, array order and duplicates.

There is no supported `EXISTS` predicate. Within a project/type/creator scope, ordered types can express absence with `not(gte(name, minimumOfStoredType))`; use a documented `has_<field>: bool(...)` projection for other types or when explicit null semantics matter. Request all attributes before inferring absence; see [typed predicates](../arkiv-query/SKILL.md).

`createdAt`, `updatedAt` and `expiresAt` metadata are block heights. Store application time separately as `created_at: u64(milliseconds)` with a declared clock/timezone policy.

## Worked marketplace model

This creates a listing, then its tag relationships in a second transaction. Run it only with an authorized, funded Tiramisu wallet. The caller supplies a stable application ID, exact price, project, parent lifetime, tag-count bound and remaining-block margin. Tags have set semantics here; preserve ordinals instead when duplicates matter. The result is not an upsert or uniqueness guarantee.

```typescript
import { createWalletClient, createPublicClient, ExpirationTime, type Expiry } from '@arkiv-network/sdk';
import { addr, bool, i32, key, str, u64, u256 } from '@arkiv-network/sdk/attr';
import { tiramisu } from '@arkiv-network/sdk/chains';
import type { Address } from 'viem';

type Wallet = ReturnType<typeof createWalletClient>;
type Reader = ReturnType<typeof createPublicClient>;
type ModelPolicy = { project: string; expires: Expiry; maxTags: number; minRemainingBlocks: bigint };
type Listing = {
  listing_id: string;
  seller: Address;
  price_minor: bigint;
  currency: string;
  title: string;
  tags: string[];
  created_at: bigint;
};

export function listingInput(listing: Listing, policy: ModelPolicy) {
  return {
    payload: new TextEncoder().encode(JSON.stringify({
      title: listing.title,
      tags: listing.tags,
    })),
    contentType: 'application/json',
    attributes: {
      project: str(policy.project),
      entity_type: str('listing'),
      schema_version: i32(1),
      listing_id: str(listing.listing_id),
      seller: addr(listing.seller),
      price_minor: u256(listing.price_minor),
      currency: str(listing.currency),
      active: bool(true),
      created_at: u64(listing.created_at),
    },
    expires: policy.expires,
  };
}

export async function createListingAndTags(
  reader: Reader, wallet: Wallet, listing: Listing, policy: ModelPolicy,
) {
  if (wallet.chain?.id !== tiramisu.id || reader.chain?.id !== tiramisu.id) {
    throw new Error('Both clients must use Tiramisu');
  }
  if (!policy.project || !Number.isSafeInteger(policy.maxTags) || policy.maxTags < 0 ||
      policy.minRemainingBlocks < 1n || listing.tags.length > policy.maxTags) {
    throw new Error('Configure a project, bounded tag count and positive remaining-block margin');
  }
  // Validate every tag and the parent before the first paid transaction.
  const tagValues = [...new Set(listing.tags)].map(tag => str(tag));
  const input = listingInput({ ...listing, tags: tagValues.map(tag => tag.value) }, policy);
  const parent = await wallet.createEntity(input);
  if (tagValues.length === 0) return { parent, tags: undefined };
  const head = await reader.getBlockNumber({ cacheTime: 0 });
  if (parent.expiresAt - head < policy.minRemainingBlocks) {
    throw new Error(`Parent ${parent.entityKey} from ${parent.txHash} is too near expiry; reconcile it before continuing`);
  }
  const tags = await wallet.executeBatch({
    creates: tagValues.map((tag) => ({
      payload: new Uint8Array(),
      contentType: 'application/octet-stream',
      attributes: {
        project: input.attributes.project,
        entity_type: str('listing_tag'),
        schema_version: i32(1),
        listing_id: input.attributes.listing_id,
        listing_key: key(parent.entityKey),
        tag,
      },

From Arkiv-Network/skills, MIT.

More from Arkiv-Network/skills

Signals

Stars
1
Forks
1
Open issues
9
Last commit (this folder)
Oct 16, 2026 (12 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from Arkiv-Network

Cite this page

arkiv-data-modeling skill. Agent Mart. https://agentmart.dev/skills/arkiv-network-arkiv-data-modeling (last updated 2026-10-24)