.config/opencode/skill/gremlin/SKILL.md
Write Gremlin graph traversal queries for Neptune using the gremlin-go driver patterns in this codebase
npx skillsauth add jm96441n/dotfiles gremlinInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill helps write Gremlin graph traversal queries using the github.com/apache/tinkerpop/gremlin-go/v3/driver library against AWS Neptune. The codebase has a two-layer architecture:
internal/storage/gremlin/store.go) - Low-level connection managementinternal/storage/graph/store.go) - Higher-level node/edge operationsAlways obtain traversals through the Store, specifying read-only or read-write:
// For read operations
g, err := s.gremlinStore.ReadOnlyTraversal(customerID)
// For write operations
g, err := s.gremlinStore.ReadWriteTraversal(customerID)
The customerID is used as a partition key for multi-tenancy via PartitionStrategy.
These internal properties are prefixed with _ and managed automatically:
| Property | Constant | Purpose |
|----------|----------|---------|
| _modified_time | gremlin.ModifiedTimeProperty | Last modification timestamp |
| _owner | gremlin.OwnerProperty | Resource owner identifier |
| CustomerID | gremlin.PartitionKey | Multi-tenant partition key |
result, err := g.V(nodeID).ValueMap().With(gremlingo.WithOptions.Tokens).ToList()
g.V().HasLabel("INSTANCE", "SECURITY_GROUP")
g.V().Has("name", gremlingo.P.Eq("my-resource"))
g.V().Has(gremlin.ModifiedTimeProperty, gremlingo.P.Gte(modTime))
g.V(sourceID).OutE("ATTACHES_TO").InV()
g.V(destID).InE("BELONGS_TO").OutV()
g.V(source).OutE(label).Where(gremlingo.T__.InV().HasId(dest))
g.E().
Project("id", "label", "mod", "out", "in", "customer", "owner").
By(gremlingo.T.Id).
By(gremlingo.T.Label).
By(modifiedTimeProperty).
By(gremlingo.T__.OutV().Id()).
By(gremlingo.T__.InV().Id()).
By(partitionKey).
By(ownerProperty).
ToList()
Use MergeV for vertices and MergeE for edges:
// Upsert vertex
g.MergeV(map[any]any{gremlingo.T.Id: nodeID}).
Option(gremlingo.Merge.OnCreate, map[any]any{
gremlingo.T.Label: label,
gremlingo.T.Id: id,
"prop1": gremlingo.CardinalityValue.Single(value),
}).
Option(gremlingo.Merge.OnMatch, updateTraversal).
ToList()
// Upsert edge
g.MergeE(map[any]any{
gremlingo.T.Label: edgeLabel,
gremlingo.Direction.To: destNodeID,
gremlingo.Direction.From: sourceNodeID,
}).
Option(gremlingo.Merge.OnCreate, createMap).
Option(gremlingo.Merge.OnMatch, updateTraversal).
Next()
Only update if the incoming data is newer:
gremlingo.T__.Choose(
gremlingo.T__.Or(
gremlingo.T__.Not(gremlingo.T__.Has(modifiedTimeProperty)),
gremlingo.T__.Values(modifiedTimeProperty).Is(gremlingo.P.Lt(newModTime)),
),
// If true: update
updateTraversal,
// Else: no-op
gremlingo.T__.Identity(),
).Constant(map[any]any{})
Use gremlingo.T__ for anonymous traversals (filter conditions, nested steps):
// Check property exists
gremlingo.T__.Has("propertyName")
// Check property does not exist
gremlingo.T__.HasNot("propertyName")
// Combine conditions
gremlingo.T__.And(condition1, condition2)
gremlingo.T__.Or(condition1, condition2)
// Delete a vertex (also removes connected edges)
g.V(nodeID).Drop().Iterate()
// Delete an edge
g.V(sourceID).OutE(label).Where(gremlingo.T__.InV().HasId(destID)).Drop().Iterate()
// Clear all data for a customer
g.E().Drop().Iterate()
g.V().Drop().Iterate()
The query API uses path traversals for returning connected subgraphs:
g.V().
HasLabel("EC2_INSTANCE").
OutE("ATTACHES_TO").InV().
Order().By(gremlingo.T.Id).
Range(low, high).
Path().By(gremlingo.T__.ElementMap()).
ToList()
For atomic multi-step operations, use transactions:
// Open transaction
tx, gts, err := s.gremlinStore.ReadWriteTxTraversal(customerID)
// Perform operations using gts...
// Commit or rollback
err = tx.Commit()
// or
err = tx.Rollback()
The graph.Store provides higher-level transaction management:
s.OpenTx(customerID)
// ... operations ...
s.CommitTx(customerID)
| Predicate | Usage |
|-----------|-------|
| gremlingo.P.Eq(val) | Equals |
| gremlingo.P.Neq(val) | Not equals |
| gremlingo.P.Lt(val) | Less than |
| gremlingo.P.Lte(val) | Less than or equal |
| gremlingo.P.Gt(val) | Greater than |
| gremlingo.P.Gte(val) | Greater than or equal |
Results come back as []*gremlingo.Result. Extract data like:
results, err := g.V().ToList()
for _, result := range results {
data, ok := result.Data.(map[any]any)
// Process data...
}
// For single result
result, err := g.V(id).Next()
Use testutil.SetupDataStores to get a real Gremlin container:
func TestMyGremlinQuery(t *testing.T) {
t.Parallel()
ctx := context.Background()
ds := testutil.SetupDataStores(ctx, t)
// ds.GremlinStore is a *gremlin.Store
// ds.GraphStore is a *graph.Store
}
ToList() or Iterate() - These terminate the traversal and return the connection to the poolValueMap(), values come back as []anyany type, always check caststime.Time directly, it's serialized correctlyinternal/storage/gremlin/store.go - Connection and traversal managementinternal/storage/graph/store.go - Node/edge CRUD operationsinternal/queryapi/processor.go - Complex query building for the Query APItools
Protocol for properly ending a coding session - ensures all work is committed, pushed, and handed off correctly.
tools
Prefer Jujutsu (jj) over git for version control. Use squash workflow pattern where commits are described first, then changes are made in a scratch child commit and squashed into the parent.
development
# Jira Skill Guidelines for creating and managing Jira issues for HashiCorp projects. ## InfraGraph Project (IG) ### Project Information - **Project Key**: `IG` - **Team Field**: `customfield_10001` - **Default Team Value**: `"InfraGraph-Graph Engine"` ### Creating Issues When creating Jira issues for the InfraGraph project, always include the team field: ```python jira_create_issue( project_key="IG", summary="Task summary", issue_type="Task", description="Task description
development
Guide for writing ast-grep rules to perform structural code search and analysis. Use when users need to search codebases using Abstract Syntax Tree (AST) patterns, find specific code structures, or perform complex code queries that go beyond simple text search.