Skip to content

Conversation

@drogus
Copy link
Collaborator

@drogus drogus commented Oct 7, 2025

This is a draft of the new functionality for spacetime init. In order to run it with built-in templates you have to set the path to the config file:

export SPACETIMEDB_CLI_TEMPLATES_FILE=crates/cli/.init-templates.json

In the future it will fetch the list from GH.

A few notes:

  • the previous functionality of spacetime init does not work at the moment
  • the code needs a bit more cleanup and tests before merging
  • there is a bit of a mix in how we generate empty server and client projects. For Rust we use the existing way of generating. For TypeScript we clone an empty project from the repo. I wanted to play with both ways of doing things, and I'm still not sure which is better. Generation in Rust means that the generated code will match the CLI version and not necessarily whatever is in Git. On the other hand, for the builtin templates we will be fetching the newest version from GH, which I guess might also not what we want, ie. we probably want only stable templates. More discussion is needed here
  • we use spacetimedb directory for the server files
  • I don't particularly like the inability to disable interactive mode easily. We discussed disabling it by default if all of the required arguments are passed, but I don't think it's feature proof. For example, if someone relies on a non-interactive mode, and we add a new required argument, instead of printing a message missing --foo, we will automatically launch interactive mode, which is harder to debug. That's why I think I'd prefer to implement --non-interactive argument
  • it's kind of hard to keep the legacy behaviour. If you don't pass any arguments, we go into interactive mode. In the legacy version, we would print required arguments. If someone passes --lang or --project-path explicitly, I guess we could run the legacy workflow, but not sure if it's worth it, as the command was marked as unstable anyway
  • the project path defaults to the project name, but I think we should probably replace change whitespaces to dashes, or at least ask for the project path with the project name being the default (or both)

@drogus drogus self-assigned this Oct 7, 2025
@drogus drogus marked this pull request as draft October 7, 2025 10:55
@drogus drogus force-pushed the drogus/spacetime-init branch 18 times, most recently from c022d34 to ea0f0f7 Compare October 15, 2025 20:52
@drogus drogus force-pushed the drogus/spacetime-init branch from ea0f0f7 to e536cc3 Compare October 15, 2025 20:53
@drogus drogus force-pushed the drogus/spacetime-init branch from 10f14ee to cc118cc Compare October 16, 2025 11:49
It was added first when the requirements were different. At the moment
we only allow to chose server-lang if template is not provided
@drogus drogus force-pushed the drogus/spacetime-init branch from dfa4da7 to db22a7f Compare October 23, 2025 13:24
}

let cursorrules_content = embedded::get_cursorrules();
let cursorrules_path = project_path.join(".cursorrules");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the cursorrules_content should go in .cursor/rules/spacetime-rules.mdc. (kebab case is preferred)

.cursorrules is deprecated


```bash
spacetime init --lang csharp my-project-directory
spacetime init --non-interactive --name my-spacetimedb-project --server-lang csharp my-project-directory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several suggestions:

  1. --name my-spacetimedb-project my-spacetimedb-directory is a little redundant, let's make it so that the parameter is called --project-path instead and that parameter tells you where you're going put the project. Let's make the positional argument the project name (more in line with what spacetime publish does). Let's make it so that if you do not specify a project path, it creates a directory in the current directory with the same name as the project name.
  2. Let's leave off --non-interactive in the docs, so it might actually go into interactive mode for some stuff.
  3. Let's rename --server-lang to --lang (I'm less sure about this change. I would be okay to keep it --server-lang if we made the other changes).

So this line would become:

spacetime init --lang csharp my-spacetimedb-project

Copy link
Collaborator

@jdetter jdetter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some UX questions/nits about github templates, I'm still reviewing

template_type: TemplateType::GitHub,
server_lang: None,
client_lang: None,
github_repo: Some(template_str.to_string()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check to see if this looks like a URL here? Like if someone just mistypes a template name we will end up here too no?

format!("https://github.com/{}", repo_input)
} else {
anyhow::bail!("Invalid repository format. Use 'owner/repo' or full URL");
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone wants to use a template from a private repo or they just want to use SSH auth I think it would be nice to support that here. e.g. if someone passed this as their template URL:

# Either of these should work
[email protected]/clockworklabs/PrivateTemplate
ssh://[email protected]/clockworklabs/PrivateTemplate

}

fn clone_github_template(repo_input: &str, target: &Path) -> anyhow::Result<()> {
let repo_url = if repo_input.starts_with("http") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wouldn't catch URLs like:

github.com/clockworklabs/MyTemplate

Also do we want to support pointing to local repo as well? Something like:

../clockwork/SomeTemplateImTesting

}
}

fn slugify(name: &str) -> String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not just want to use the convert_case crate for this instead? Then you can just:

name.to_case(Case::Kebab)

Plus we already use this dependency anyway

1 => Some("pnpm"),
2 => Some("yarn"),
3 => Some("bun"),
_ => None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the user selected "other" here we should prompt them for the package manager they want to use

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not quite so simple, I think in this case they are doing something that 99.9% of users won't do, so we should leave them to their own devices.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the "other" option then?

Copy link
Collaborator

@jdetter jdetter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More review

println!(" {} - {}", template.id, template.description);
}
println!();
loop {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop isn't used

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-any To be landed in any release window

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants