Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e6b8009
chore: deploy patch
MasterPtato Feb 27, 2026
da30a87
feat: add KV range operations (listRange, deleteRange, scan) (#4372)
NathanFlurry Mar 6, 2026
88a1c14
Update landing page title and subtitle (#4377)
NathanFlurry Mar 8, 2026
90d7121
refactor(workflow-engine): optimize loop history pruning (#4370)
NathanFlurry Mar 8, 2026
4a64507
refactor: explicit protocol version conversions (#4380)
NathanFlurry Mar 8, 2026
d095733
docs: update AI agent examples to showcase run handler pattern (#4382)
NathanFlurry Mar 8, 2026
870b7b3
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
a159316
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
52dc114
chore: flatten runtime config
MasterPtato Feb 27, 2026
d4632aa
feat: add KV range operations (listRange, deleteRange, scan) (#4372)
NathanFlurry Mar 6, 2026
c6994af
refactor(workflow-engine): optimize loop history pruning (#4370)
NathanFlurry Mar 8, 2026
69e2b1d
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
a6d04e9
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
d5355c1
fix(api): make actor destroy wait for ack
MasterPtato Feb 27, 2026
8dadaf0
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
7bae8ed
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
7bdc25f
fix(udb): add txn tagging
MasterPtato Feb 27, 2026
40301f5
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
b622eec
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
365fb94
chore: bump rivetkit protocol version
MasterPtato Feb 27, 2026
1e7376e
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
421d108
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
76cc39a
fix(ups): formalize subjects
MasterPtato Mar 2, 2026
54a5e92
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
707d36b
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
2bd0bd6
fix(api): properly dedup name list responses
MasterPtato Mar 3, 2026
75c9b65
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
a0fc6cb
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
fd90f6e
fix(pb): clear actor reschedule ts on alloc
MasterPtato Mar 3, 2026
1ff3c45
fix(ci): stabilize pr actions (#4381)
NathanFlurry Mar 8, 2026
a7a2596
feat(frontend): polish onboarding UI (#4376)
NicholasKissel Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .claude/skills/git-spice-merge-my-stack/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
name: git-spice-merge-my-stack
description: Merge a stacked git-spice branch chain with gh by retargeting each PR to main and merging bottom to top, including conflict recovery via rebase.
license: MIT
compatibility: Requires GitHub CLI (gh), git, and push access.
metadata:
author: rivet
version: "1.0"
---

Merge a stacked PR chain.

**Input**: A target branch in the stack (usually the top branch to merge through).

**Goal**: Merge all PRs from the bottom of that stack up to the target branch.

## Steps

1. **Resolve the target PR**
- Find PR for the provided branch:
- `gh pr list --state open --head "<target-branch>" --json number,headRefName,baseRefName,url`
- If no open PR exists, stop and report.

2. **Build the stack chain down to main**
- Start at target PR.
- Repeatedly find the PR whose `headRefName` equals the current PR `baseRefName`.
- Continue until base is `main` or no parent PR exists.
- If chain is ambiguous, stop and ask the user which branch to follow.

3. **Determine merge order**
- Merge from **bottom to top**.
- Example: `[bottom, ..., target]`.

4. **For each PR in order**
- Retarget to `main` before merge:
- `gh pr edit <pr-number> --base main`
- Merge with repository-compatible strategy:
- Try `gh pr merge <pr-number> --squash --delete-branch=false`
- If merge fails due conflicts:
- `gh pr checkout <pr-number>`
- `git fetch origin main`
- `git rebase origin/main`
- Resolve conflicts. If replaying already-upstream commits from lower stack layers, prefer `git rebase --skip`.
- Continue with `GIT_EDITOR=true git rebase --continue` when needed.
- `git push --force-with-lease origin <head-branch>`
- Retry `gh pr merge ... --squash`.

5. **Verify completion**
- Confirm each PR in chain is merged:
- `gh pr view <pr-number> --json state,mergedAt,url`
- Report final ordered merge list with PR numbers and timestamps.

## Guardrails

- Always merge in bottom-to-top order.
- Do not use merge commits if the repo disallows them.
- Do not delete remote branches unless explicitly requested.
- If a conflict cannot be safely resolved, stop and ask the user.
- If force-push is required, use `--force-with-lease`, never `--force`.
- After finishing, return to the user's original branch unless they asked otherwise.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,4 @@ Serverless, containers, or your own servers — Rivet Actors work with your exis

## License

[Apache 2.0](LICENSE)
[Apache 2.0](LICENSE)
167 changes: 64 additions & 103 deletions engine/artifacts/config-schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 22 additions & 12 deletions engine/packages/api-peer/src/actors/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,36 @@ use rivet_util::Id;
)]
#[tracing::instrument(skip_all)]
pub async fn delete(ctx: ApiCtx, path: DeletePath, query: DeleteQuery) -> Result<DeleteResponse> {
// Get the actor first to verify it exists
let actors_res = ctx
.op(pegboard::ops::actor::get::Input {
// Subscribe before fetching actor data
let mut destroy_sub = ctx
.subscribe::<pegboard::workflows::actor::DestroyComplete>(("actor_id", path.actor_id))
.await?;

let (actors_res, namespace_res) = tokio::try_join!(
// Get the actor to verify it exists
ctx.op(pegboard::ops::actor::get::Input {
actor_ids: vec![path.actor_id],
fetch_error: false,
})
.await?;
}),
ctx.op(namespace::ops::resolve_for_name_global::Input {
name: query.namespace,
}),
)?;

let actor = actors_res
.actors
.into_iter()
.next()
.ok_or_else(|| pegboard::errors::Actor::NotFound.build())?;

// Verify the actor belongs to the specified namespace
let namespace = ctx
.op(namespace::ops::resolve_for_name_global::Input {
name: query.namespace,
})
.await?
.ok_or_else(|| namespace::errors::Namespace::NotFound.build())?;
// Already destroyed
if actor.destroy_ts.is_some() {
return Err(pegboard::errors::Actor::NotFound.build());
}

let namespace = namespace_res.ok_or_else(|| namespace::errors::Namespace::NotFound.build())?;

// Verify the actor belongs to the specified namespace
if actor.namespace_id != namespace.namespace_id {
return Err(pegboard::errors::Actor::NotFound.build());
}
Expand All @@ -56,6 +64,8 @@ pub async fn delete(ctx: ApiCtx, path: DeletePath, query: DeleteQuery) -> Result
actor_id=?path.actor_id,
"actor workflow not found, likely already stopped"
);
} else {
destroy_sub.next().await?;
}

Ok(DeleteResponse {})
Expand Down
1 change: 1 addition & 0 deletions engine/packages/api-public/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ epoxy.workspace = true
futures-util.workspace = true
gas.workspace = true
include_dir.workspace = true
indexmap.workspace = true
namespace.workspace = true
pegboard.workspace = true
reqwest.workspace = true
Expand Down
14 changes: 3 additions & 11 deletions engine/packages/api-public/src/actors/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,18 @@ async fn list_inner(ctx: ApiCtx, query: ListQuery) -> Result<ListResponse> {
.await?
.ok_or_else(|| namespace::errors::Namespace::NotFound.build())?;

let limit = query.limit.unwrap_or(100);

// Fetch actors
let mut actors = fetch_actors_by_ids(
&ctx,
actor_ids,
query.namespace.clone(),
query.include_destroyed,
None, // Don't apply limit in fetch, we'll apply it after cursor filtering
Some(limit),
)
.await?;

// Apply cursor filtering if provided
if let Some(cursor_str) = &query.cursor {
let cursor_ts: i64 = cursor_str.parse().context("invalid cursor format")?;
actors.retain(|actor| actor.create_ts < cursor_ts);
}

// Apply limit after cursor filtering
let limit = query.limit.unwrap_or(100);
actors.truncate(limit);

let cursor = actors.last().map(|x| x.create_ts.to_string());
Expand Down Expand Up @@ -208,8 +202,6 @@ async fn list_inner(ctx: ApiCtx, query: ListQuery) -> Result<ListResponse> {
// Sort by create ts desc
actors.sort_by_cached_key(|x| std::cmp::Reverse(x.create_ts));

// Shorten array since returning all actors from all regions could end up returning `regions *
// limit` results, which is a lot.
actors.truncate(limit);

let cursor = actors.last().map(|x| x.create_ts.to_string());
Expand Down
Loading
Loading