Skip to content

Assets

Assets are data objects stored in the cloud with a filesystem-like interface. In addition to basic blob storage, there are additional conveniences for you and your LLM: syncing changed data down, listening for changes to assets, temporarily making assets available locally, and revision control.

Create an asset

To create or open an existing asset, use:

/asset <name>
/a <name>

Asset names as paths

Asset names can mimic paths by using forward slash, e.g. /asset a/b/c

This opens your configured editor (defaults to vim) to write the contents.

To skip the editor, write a multi-line command (Alt + Enter or Option + Enter) to set the contents:

/asset <name>
test
1 2 3

To use another editor:

/asset <name> <editor-cmd>

Load an asset

To load an asset into a conversation, use:

/asset-load <name>

Tab complete for asset names

When specifying asset names, use tab for auto-completion.

To load an asset and print its contents in the repl, use:

/asset-view <name>

Similar local files loaded with /load, loaded assets are retained after a /reset.

Temporary local copy of asset

It's undesirable to load an asset into a conversation when the data is better transformed by a function written by the LLM rather than by the LLM itself.

Having an LLM transform data is prone to many issues: slow data processing, costly output tokens, hallucinations, exceeding the context window, and lack of support for non-unicode data.

The solution is to make a temporary copy of an asset and have the LLM operate on the file:

/asset-temp <name>

This makes a temporary local copy of the asset and adds the file path to the conversation.

Here's an example processing The Odyssey by Homer:

[0]: /asset-temp book/odyssey.txt
Asset 'book/odyssey.txt' copied to '/var/folders/nv/ytdlylsn7kn_x53vcy4pz1xr0000gn/T/asset_RPcI7k.txt'
[2] !sh count occurrences of ulysses
↓↓↓

grep -io 'ulysses' /var/folders/nv/ytdlylsn7kn_x53vcy4pz1xr0000gn/T/asset_RPcI7k.txt | wc -l
⚙ ⚙ ⚙

580

The temporary file is automatically cleaned up when the conversation ends.

To make copies of the most recent n revisions of an asset, try:

/asset-temp <name> <n>

Syncing assets locally

To sync local copies of assets, use:

/asset-sync-down <prefix> <path>

This does a one-way sync of all assets with the given prefix to a local path. Asset names are reproduced on the local filesystem and forward slashes are converted to folders. Existing assets are not downloaded again unless their contents have changed.

No information is added to the conversation history. You will need to inform the LLM of relevant files. For example, by listing the files: !!ls <path>

Any assets with metadata will have those synced as well as separate files with a .metadata extension.

To generate a link to an asset that's valid for 24 hours, use:

/asset-link <name>

Iterating through revisions

To see revisions of an asset, use:

/asset-revisions <name>

This is interactive and requires input to jump to each revision. To simply dump count revisions to the conversation, use:

/asset-revisions <name> <count>

Import or export assets

To import an asset from a local file:

/asset-import <name> <path>

To export an asset to a local file:

/asset-export <name> <path>

Listing assets

To list assets, use:

/asset-list [<prefix>]
/ls [<prefix>]

Specifying a prefix filters the result set. The prefix can be arbitrary and does not need to be aligned with a folder segment.

Public assets

Public assets start with a forward slash followed by a username (/<username>):

For example, substituting your username you can create a public file:

/asset /<username>/public.txt

Any other user can view it with:

/asset-view /<username>/public.txt

Public assets shortcut

You can also use // as a shortcut to refer to your own public asset path. For example, /asset //public.txt is equivalent to /asset /<username>/public.txt. This makes it easier to access your public assets and lets you write task steps that are generic to the logged-in account.

Assets can be searched semantically based on their contents:

/asset-search cook salmon

The search is powered by embeddings on the content and the title metadata key if it's set. The latter is especially important if the content is non-unicode.

Usage with /exec

When executing a shell command, use @name to reference an asset. The asset will be transparently downloaded into a temporary file.

[0] !!cat @/hai/changelog | grep -A 2 v1.3.0
equivalent to:
[0] !!grep -A 2 v1.3.0 @/hai/changelog
## v1.3.0

- Add syntax highlighting for code blocks.

Note: !! is shorthand for /exec.

If a shell redirects (> or >>) to an @asset, the output file will be uploaded as well.

[0] !!grep -A 2 v1.3.0 @/hai/changelog > @changes-v1.3.0

This processes a public asset from the hai account and saves a filtered version to the changes-v1.3.0 private asset.

Limitations

The implementation uses simple string substitution to replace @asset markers with temporary files. Complex shell operations involving quotes or escapes around asset references may not work as expected.

Write conflicts

When the same asset is modified simultaneously by two separate hai processes, a write conflict occurs. The version that loses the race will be preserved as a new asset with the same name as the original but with a random suffix.

An easy way to see the difference is to:

!!diff @file @file(suffix)

Metadata

Each asset can have a JSON object associated with it to store metadata:

Command Description
/asset-md-get <name> Fetches metadata for an asset and adds it to the conversation.
/asset-md-set <name> <json> Sets the entire metadata blob.
/asset-md-set-key <name> <key> <value> Sets/replaces a metadata key.
/asset-md-del-key <name> <key> Deletes a metadata key.

If the title metadata key is set, it's shown in /asset-list and /asset-search in [] brackets.

🙋 Help Wanted

Interested in using metadata to make asset encryption the default way of life? All ideas welcome. Please reach out or open an issue.

Asset Push & ACL

Your public assets (prefixed by your username /username/...) can have ACLs set so that an asset can be used as a write-only "asset/document drop".

/asset-acl /ken/hai-feedback deny:read-data
/asset-acl /ken/hai-feedback allow:push-data

With these ACLs, any user can push data (/asset-push) into the /ken/hai-feedback asset, but no one except the owner can read what's been pushed.

The owner (user ken in this example) can read the contents of /ken/hai-feedback using /asset-list-revisions and can access revisions with /asset-get-revision.

Listening for changes

/asset-listen <name> can be used to block the REPL until a change to the asset. You can test this by:

# Console 1 (create asset)
/asset test-listen

# Console 2 (listen for changes -- blocking)
/asset-listen test-listen

# Console 1 (modify, unblocking console 2)
/asset test-listen

For an example of sending emails based on asset changes, see the hai/email-asset-updates task: /task hai/email-asset-updates

Note that the API exposes a websockets interface that pushes notifications when changes occur.

Collapsing Folders

The underlying asset store uses a key-value structure. While asset keys may contain forward slashes to resemble directory paths, these are purely cosmetic.

By default, when listing your assets, they appear as a flat list:

[0] /ls
a/b/c
a/b/d
a/b/e/f

To make browsing easier, you can choose to "collapse" specific folders:

  • /asset-folder-collapse <path> - Collapse a folder when listing a parent prefix.
  • /asset-folder-expand <path> - Uncollapse a folder when listing a parent prefix. Note that all folders are expanded by default.
  • /asset-folder-list [<prefix>] - List all collapsed folders with the given path prefix.

Collapsing the a/b folder:

[1] /asset-collapse a/b

Now, listing the root shows the collapsed folder:

[2] /ls
a/b📁

To view the contents of the collapsed folder, list it directly:

[3] /ls a/b/
a/b/c
a/b/d
a/b/e/f

There's a limit of 100 collapsed folders each for your private and public assets.

Quota

Each account gets 1GB of asset storage.

Revisions

The size of each revision is counted towards your storage. When an asset is removed, the total size of all of its revisions is removed from your quota.

To increase your account's storage quota, see /account-subscribe.