Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ agora init my-nextjs-demo --template nextjs
| Next.js video app | `agora init my-nextjs-demo --template nextjs` | A cloned Next.js quickstart, project binding, and `.env.local` |
| Python voice agent | `agora init my-python-demo --template python` | A Python quickstart with Agora credentials written for the backend |
| Go token service | `agora init my-go-demo --template go` | A Go server quickstart with project metadata and env wiring |
| Android conversational AI app | `agora quickstart create my-android-demo --template android` | A cloned Android quickstart on the `rest-api` branch |

## Install

Expand Down
2 changes: 1 addition & 1 deletion docs/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Check project health: agora project doctor --json
- **Project Management**: Initialize, configure, and validate Agora projects
- **JSON Output**: All commands support --json for automation and scripting (see Automation Notes below for one documented exception)
- **Stable Exit Codes**: Consistent error codes for CI/CD integration
- **Template System**: Quick-start templates for Next.js, Python, and Go (see `agora init --help` for the current catalog)
- **Template System**: Quick-start templates for Next.js, Python, and Go (see `agora init --help` for the init-capable catalog); Android is clone-only for now and appears in `agora quickstart list`
- **Cross-Platform**: macOS, Linux, Windows support
- **Agentic discovery**: `agora introspect --json` and `agora --help --all --json` emit the same machine-readable command tree
- **MCP server**: `agora mcp serve` exposes the CLI as Model Context Protocol tools for agents
Expand Down
5 changes: 4 additions & 1 deletion internal/cli/integration_quickstart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ func TestCLIQuickstartListAndCreate(t *testing.T) {
if list.exitCode != 0 || !strings.Contains(list.stdout, `"id":"nextjs"`) || !strings.Contains(list.stdout, `"id":"python"`) || !strings.Contains(list.stdout, `"id":"go"`) {
t.Fatalf("unexpected quickstart list result: %+v", list)
}
if !strings.Contains(list.stdout, `"id":"android"`) {
t.Fatalf("expected android quickstart in list result: %+v", list)
}
listAll := runCLI(t, []string{"quickstart", "list", "--show-all", "--json"}, cliRunOptions{env: map[string]string{
"XDG_CONFIG_HOME": configHome,
"AGORA_LOG_LEVEL": "error",
}})
if listAll.exitCode != 0 || !strings.Contains(listAll.stdout, `"id":"go"`) {
if listAll.exitCode != 0 || !strings.Contains(listAll.stdout, `"id":"go"`) || !strings.Contains(listAll.stdout, `"id":"android"`) {
t.Fatalf("unexpected quickstart list --show-all result: %+v", listAll)
}

Expand Down
26 changes: 23 additions & 3 deletions internal/cli/quickstart.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type quickstartTemplate struct {
Description string
Runtime string
RepoURL string
Ref string
DocsURL string
DetectPaths []string
EnvExamplePath string
Expand Down Expand Up @@ -79,6 +80,21 @@ func quickstartTemplates() []quickstartTemplate {
SupportsInit: true,
Available: true,
},
{
ID: "android",
Title: "Conversational AI Android Quickstart",
Description: "Clone the official Android conversational AI quickstart.",
Runtime: "android",
RepoURL: "https://github.com/AgoraIO-Conversational-AI/agent-quickstart-android",
Ref: "rest-api",
DocsURL: "https://github.com/AgoraIO-Conversational-AI/agent-quickstart-android/tree/rest-api",
DetectPaths: []string{"settings.gradle", "gradlew", "app/src/main/AndroidManifest.xml"},
InstallCommand: "Open in Android Studio",
RunCommand: "Run from Android Studio or Gradle",
EnvDocsSummary: "Android quickstart template. Clone-only for now; env seeding is not yet wired into the CLI.",
SupportsInit: false,
Available: true,
},
}
}

Expand Down Expand Up @@ -292,11 +308,15 @@ func (a *App) quickstartCreate(template quickstartTemplate, targetDir, explicitP
if err != nil {
return nil, err
}
effectiveRef := strings.TrimSpace(ref)
if effectiveRef == "" {
effectiveRef = strings.TrimSpace(template.Ref)
}
if overrideKey != "" {
progress.emit("clone:override", fmt.Sprintf("Using repo override from %s", overrideKey), map[string]any{"repoUrl": repoURL, "envVar": overrideKey})
}
progress.emit("clone:start", "Cloning quickstart repository", map[string]any{"repoUrl": repoURL, "targetPath": absTarget, "ref": ref})
if err := cloneQuickstartRepo(repoURL, absTarget, ref); err != nil {
progress.emit("clone:start", "Cloning quickstart repository", map[string]any{"repoUrl": repoURL, "targetPath": absTarget, "ref": effectiveRef})
if err := cloneQuickstartRepo(repoURL, absTarget, effectiveRef); err != nil {
return nil, err
}
progress.emit("clone:complete", "Quickstart repository cloned", map[string]any{"targetPath": absTarget})
Expand Down Expand Up @@ -346,7 +366,7 @@ func (a *App) quickstartCreate(template quickstartTemplate, targetDir, explicitP
"title": template.Title,
"written": written,
"nextSteps": initNextSteps(template, absTarget),
"ref": ref,
"ref": effectiveRef,
}
if boundProject != nil {
result["projectId"] = boundProject.project.ProjectID
Expand Down
24 changes: 24 additions & 0 deletions internal/cli/quickstart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,27 @@ func TestQuickstartRepoURLOverride(t *testing.T) {
}
}
}

func TestQuickstartTemplatesIncludeAndroid(t *testing.T) {
var android quickstartTemplate
found := false
for _, tmpl := range quickstartTemplates() {
if tmpl.ID == "android" {
android = tmpl
found = true
break
}
}
if !found {
t.Fatal("expected android quickstart template to exist")
}
if android.RepoURL != "https://github.com/AgoraIO-Conversational-AI/agent-quickstart-android" {
t.Fatalf("unexpected android repo url: %q", android.RepoURL)
}
if android.Ref != "rest-api" {
t.Fatalf("unexpected android default ref: %q", android.Ref)
}
if !android.Available || android.SupportsInit {
t.Fatalf("unexpected android flags: available=%v supportsInit=%v", android.Available, android.SupportsInit)
}
}
Loading