Install
$ agentstack add skill-geobrowser-geo-skills-geo-query ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Geo Knowledge Graph — Querying
Query and explore entities, types, properties, and relations in the Geo knowledge graph via its GraphQL API.
When to apply
Use this skill when the user wants to:
- Look up an entity by ID.
- Search for entities of a given type (optionally scoped to a space).
- Explore what properties and relations an entity has.
- Discover the schema for an unfamiliar entity type before publishing.
- Find type, property, or relation type IDs.
API basics
- Endpoint:
https://testnet-api.geobrowser.io/graphql - Method:
POSTwithContent-Type: application/json - Auth: none required for reads.
- UUIDs: 32-char hex, no dashes (e.g.
4faff0b210cb49958e20109409b8699c). - Browser links:
https://www.geobrowser.io/space/{spaceId}/{entityId}.
Core concepts (compact)
- Entity: a unique node in the graph (person, place, article, etc.). Has an ID,
name,description,types,values, andrelations. - Property: a typed attribute on an entity (
text,date,boolean,decimal,integer,float,url). - Relation: a typed edge between two entities. Relations are themselves entities — they can have their own properties.
- Type: a category (
Person,Article, …). Types define a schema of default properties that every entity of that type inherits. - Space: an independent community/topic scope. An entity can live in multiple spaces; each has its own perspective.
Full conceptual details: see reference.md.
List query: entities vs entitiesConnection
There are two list queries with the same top-level args (typeId, spaceId, typeIds, spaceIds, filter, first, offset, orderBy) but different shapes. Choose based on result set size:
| | entities | entitiesConnection | | ------------ | ------------------------------------------------- | ------------------------------------------- | | Return shape | flat array | { nodes, edges, pageInfo, totalCount } | | Pagination | first + offset (capped at offset 1000) | first + cursor (after/before) | | Use when | small, bounded lookups; default for > { const out: Array = []; let cursor: string | null = null;
while (true) { const afterClause = cursor ? after: "${cursor}" : ""; const res = await fetch("https://testnet-api.geobrowser.io/graphql", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: { entitiesConnection(typeId: "${typeId}", spaceId: "${spaceId}", first: 500 ${afterClause}) { nodes { id name } pageInfo { hasNextPage endCursor } } }, }), }); const { data } = await res.json(); const conn = data.entitiesConnection; out.push(...(conn?.nodes ?? [])); if (!conn?.pageInfo?.hasNextPage) break; cursor = conn.pageInfo.endCursor; } return out; }
## Filtering
The `filter` arg accepts `EntityFilter` for field-level conditions:
```graphql
{
entities(typeId: "TYPE_ID", filter: { name: { startsWithInsensitive: "Bitcoin" } }, first: 20) {
id
name
}
}
Common EntityFilter fields:
id—UUIDFilter(usesis/isNot/in; NOTequalTo).name,description,createdAt,updatedAt—StringFilter(startsWithInsensitive,includesInsensitive,equalTo).spaceIds,typeIds—UUIDListFilter(anyEqualTo).relations,backlinks—EntityToManyRelationFilter(some,none,every).values—EntityToManyValueFilter.and,or,not.
CRITICAL — scope relation filters by space. Cross-space relation filters can return INTERNAL_SERVER_ERROR on the server. Always include spaceId inside relation filters:
relations: { some: { spaceId: { is: "SPACE_ID" }, toEntity: { ... } } }
Prefer none over every for exclusion. every means "all items must match the full condition" and misbehaves when items have different field values. Use none for "there is no X where Y":
# "entity has no name value"
values: { none: { propertyId: { is: NAME_PROP_ID }, text: { isNull: false } } }
If complex filters return 500s, reduce first from 500 → 100 → 50.
Schema discovery workflow
When you need to publish or understand an entity type you haven't seen before, inspect an existing entity of that type to learn the schema. Do this before assuming any property/relation IDs.
- Find entities of the type (search by
typeId). - Pick one and fetch it fully (all values + relations).
- Read the property names and relation types from the result.
- Note the IDs — property IDs, relation type IDs, and
toEntityIDs for classification values.
{
entities(typeId: "86db141cf7cb471194ed39088926adb8", first: 3) {
id
name
types {
id
name
}
values(first: 50) {
nodes {
property {
id
name
}
text
date
}
}
relations(first: 50) {
nodes {
type {
id
name
}
toEntity {
id
name
}
}
}
}
}
See examples/discover-schema.md for an end-to-end walkthrough.
Finding type and property IDs by name
Type and Property are themselves types — you can query all of them:
# All type definitions
{
entities(
typeId: "e7d737c536764c609fa16aa64a8c90ad"
filter: { name: { includesInsensitive: "article" } }
first: 20
) {
id
name
}
}
# All property definitions
{
entities(
typeId: "808a04ceb21c4d888ad12e240613e5ca"
filter: { name: { includesInsensitive: "date" } }
first: 20
) {
id
name
}
}
For relation types, inspect an entity that uses them — the type { id name } field on a relation gives you the ID.
Well-known IDs
Prefer the SDK's exported constants where possible:
import { SystemIds, ContentIds } from "@geoprotocol/geo-sdk";
(SystemIds.PERSON_TYPE, SystemIds.COMPANY_TYPE, SystemIds.PROJECT_TYPE, SystemIds.EVENT_TYPE);
(ContentIds.ARTICLE_TYPE, ContentIds.TALK_TYPE, ContentIds.PODCAST_TYPE, ContentIds.TOPIC_TYPE);
Common raw IDs (for GraphQL queries):
| Name | ID | | --------------- | ---------------------------------- | | Type (meta) | e7d737c536764c609fa16aa64a8c90ad | | Property (meta) | 808a04ceb21c4d888ad12e240613e5ca | | Person | 4faff0b210cb49958e20109409b8699c | | Article | a2a5ed0cacef46b1835de457956ce915 | | Topic | 5ef5a5860f274d8e8f6c59ae5b3e89e2 |
Well-known space IDs and additional type IDs live in reference.md.
curl sanity check
curl -s --compressed 'https://testnet-api.geobrowser.io/graphql' \
-H 'Content-Type: application/json' \
-d '{"query":"{ entities(typeId: \"4faff0b210cb49958e20109409b8699c\", first: 5) { id name } }"}' | jq .
Critical gotchas — quick reference
- Offset cap 1000 on
entities/relations/values— use*Connection+ cursor for larger sets. entitiesis flat, not{ nodes { ... } }.typeId/spaceIdare top-level args, not insidefilter.- Scope relation filters by
spaceIdto avoidINTERNAL_SERVER_ERROR. UUIDFilterusesis/isNot/in, notequalTo.UUIDListFilterusesanyEqualTo.- Prefer
noneovereveryfor exclusion logic. - Values come back as typed fields (
text,date,boolean, …), not a singlevalue. - Relation
id≠entityId—idis the edge (for deletion);entityIdis the relation-as-entity (for relation properties).
More
reference.md— full filter spec, all well-known IDs, advanced patterns.examples/lookup-entity.md— walk through a single-entity fetch and what the shape looks like.examples/paginate-list.md— cursor pagination example with totalCount.examples/discover-schema.md— the schema-discovery workflow in practice.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: geobrowser
- Source: geobrowser/geo-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.