Skip to content

Commit 81dde60

Browse files
authored
Merge pull request #4 from PinataCloud/feature/templates
Feature/templates
2 parents c09c39c + fb3ff9e commit 81dde60

4 files changed

Lines changed: 337 additions & 9 deletions

File tree

‎README.md‎

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ COMMANDS:
501501
ports, p Manage agent port forwarding
502502
domains, dom Manage custom domains (beta)
503503
files Agent file operations
504-
templates, tpl Browse pre-built agent templates
504+
templates, tpl Browse and manage agent templates
505505
clawhub, hub Browse and install skills from ClawHub
506506
config, cfg Manage agent configuration
507507
update, up Manage agent openclaw updates
@@ -896,25 +896,31 @@ pinata agents tasks create --name "scheduled-job" --at "2026-04-01T12:00:00Z" --
896896

897897
#### `templates`
898898

899-
Browse pre-built agent templates that provide ready-to-use configurations.
899+
Browse and manage agent templates. Includes browsing published templates and submitting your own from a GitHub/GitLab repository.
900900

901901
```
902902
NAME:
903-
pinata agents templates - Browse pre-built agent templates
903+
pinata agents templates - Browse and manage agent templates
904904
905905
USAGE:
906906
pinata agents templates command [command options] [arguments...]
907907
908908
COMMANDS:
909-
list, l List available templates
910-
get, g Get template details
911-
help, h Shows a list of commands or help for one command
909+
list, l List available templates
910+
get, g Get template details by slug
911+
mine List templates you have submitted
912+
validate, v Validate a git repo for template submission
913+
submit, s Submit a new template from a git repo
914+
update, u Update an existing template submission (re-pull from repo)
915+
delete, d Archive a template submission
916+
branches List branches for a git repository
917+
help, h Shows a list of commands or help for one command
912918
913919
OPTIONS:
914920
--help, -h show help
915921
```
916922

917-
**Examples:**
923+
**Browsing templates:**
918924

919925
```bash
920926
# List all templates
@@ -923,10 +929,50 @@ pinata agents templates list
923929
# List featured templates only
924930
pinata agents templates list --featured
925931

932+
# Filter by category
933+
pinata agents templates list --category ai
934+
926935
# Get template details
927936
pinata agents templates get ipfs-expert
928937
```
929938

939+
**Submitting templates:**
940+
941+
Your git repo must contain a valid `manifest.json` with template metadata, a `README.md`, and a `workspace/` directory.
942+
943+
```bash
944+
# Validate your repo before submitting
945+
pinata agents templates validate https://github.com/user/my-agent-template
946+
947+
# Validate a specific branch
948+
pinata agents templates validate https://github.com/user/my-agent-template --branch develop
949+
950+
# List available branches
951+
pinata agents templates branches https://github.com/user/my-agent-template
952+
953+
# Submit the template
954+
pinata agents templates submit https://github.com/user/my-agent-template
955+
956+
# Submit from a specific branch
957+
pinata agents templates submit https://github.com/user/my-agent-template --branch develop
958+
```
959+
960+
**Managing your submissions:**
961+
962+
```bash
963+
# List your submitted templates
964+
pinata agents templates mine
965+
966+
# Update an existing submission (re-pull from repo)
967+
pinata agents templates update <template-id>
968+
969+
# Update with a new repo URL or branch
970+
pinata agents templates update <template-id> --git-url https://github.com/user/new-repo --branch main
971+
972+
# Archive a submission
973+
pinata agents templates delete <template-id>
974+
```
975+
930976
#### `clawhub`
931977

932978
Browse and install skills from ClawHub, the community skills marketplace.

‎internal/agents/templates.go‎

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,131 @@ func GetTemplate(slug string) (*TemplateDetailResponse, error) {
8383

8484
return &response, nil
8585
}
86+
87+
// ListTemplatesBySubmitter retrieves templates submitted by the authenticated user.
88+
func ListTemplatesBySubmitter() (*TemplateListResponse, error) {
89+
var response TemplateListResponse
90+
err := doTemplatesJSON(http.MethodGet, "?submittedBy=me", nil, &response)
91+
if err != nil {
92+
return nil, err
93+
}
94+
95+
formattedJSON, err := json.MarshalIndent(response.Templates, "", " ")
96+
if err != nil {
97+
return nil, errors.New("failed to format JSON")
98+
}
99+
100+
fmt.Println(string(formattedJSON))
101+
102+
return &response, nil
103+
}
104+
105+
// ValidateTemplate validates a git repo for template submission.
106+
func ValidateTemplate(gitURL, branch string) (*ValidateTemplateResponse, error) {
107+
body := SubmitTemplateBody{GitURL: gitURL}
108+
if branch != "" {
109+
body.Branch = branch
110+
}
111+
112+
var response ValidateTemplateResponse
113+
err := doTemplatesJSON(http.MethodPost, "/validate", body, &response)
114+
if err != nil {
115+
return nil, err
116+
}
117+
118+
formattedJSON, err := json.MarshalIndent(response, "", " ")
119+
if err != nil {
120+
return nil, errors.New("failed to format JSON")
121+
}
122+
123+
fmt.Println(string(formattedJSON))
124+
125+
return &response, nil
126+
}
127+
128+
// SubmitTemplate submits a new template from a git repo URL.
129+
func SubmitTemplate(gitURL, branch string) (*SubmitTemplateResponse, error) {
130+
body := SubmitTemplateBody{GitURL: gitURL}
131+
if branch != "" {
132+
body.Branch = branch
133+
}
134+
135+
var response SubmitTemplateResponse
136+
err := doTemplatesJSON(http.MethodPost, "", body, &response)
137+
if err != nil {
138+
return nil, err
139+
}
140+
141+
formattedJSON, err := json.MarshalIndent(response, "", " ")
142+
if err != nil {
143+
return nil, errors.New("failed to format JSON")
144+
}
145+
146+
fmt.Println(string(formattedJSON))
147+
148+
return &response, nil
149+
}
150+
151+
// UpdateTemplate updates an existing template submission by re-pulling from the repo.
152+
func UpdateTemplate(templateID, gitURL, branch string) (*SubmitTemplateResponse, error) {
153+
body := SubmitTemplateBody{}
154+
if gitURL != "" {
155+
body.GitURL = gitURL
156+
}
157+
if branch != "" {
158+
body.Branch = branch
159+
}
160+
161+
var response SubmitTemplateResponse
162+
err := doTemplatesJSON(http.MethodPut, "/"+templateID, body, &response)
163+
if err != nil {
164+
return nil, err
165+
}
166+
167+
formattedJSON, err := json.MarshalIndent(response, "", " ")
168+
if err != nil {
169+
return nil, errors.New("failed to format JSON")
170+
}
171+
172+
fmt.Println(string(formattedJSON))
173+
174+
return &response, nil
175+
}
176+
177+
// DeleteTemplate archives a template submission.
178+
func DeleteTemplate(templateID string) (*DeleteTemplateResponse, error) {
179+
var response DeleteTemplateResponse
180+
err := doTemplatesJSON(http.MethodDelete, "/"+templateID, nil, &response)
181+
if err != nil {
182+
return nil, err
183+
}
184+
185+
formattedJSON, err := json.MarshalIndent(response, "", " ")
186+
if err != nil {
187+
return nil, errors.New("failed to format JSON")
188+
}
189+
190+
fmt.Println(string(formattedJSON))
191+
192+
return &response, nil
193+
}
194+
195+
// ListBranches lists branches for a public git repository.
196+
func ListBranches(gitURL string) (*BranchesResponse, error) {
197+
body := BranchesBody{GitURL: gitURL}
198+
199+
var response BranchesResponse
200+
err := doTemplatesJSON(http.MethodPost, "/branches", body, &response)
201+
if err != nil {
202+
return nil, err
203+
}
204+
205+
formattedJSON, err := json.MarshalIndent(response, "", " ")
206+
if err != nil {
207+
return nil, errors.New("failed to format JSON")
208+
}
209+
210+
fmt.Println(string(formattedJSON))
211+
212+
return &response, nil
213+
}

‎internal/agents/types.go‎

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,18 +570,66 @@ type Template struct {
570570
PriceNetwork string `json:"priceNetwork"`
571571
PayToAddress *string `json:"payToAddress"`
572572
IsFree bool `json:"isFree"`
573+
Version int `json:"version,omitempty"`
574+
CreatedAt string `json:"createdAt,omitempty"`
575+
UpdatedAt string `json:"updatedAt,omitempty"`
576+
SubmittedBy *string `json:"submittedBy,omitempty"`
577+
GitURL *string `json:"gitUrl,omitempty"`
578+
GitCommitSha *string `json:"gitCommitSha,omitempty"`
579+
ReadmeHTML *string `json:"readmeHtml,omitempty"`
573580
}
574581

575582
// TemplateListResponse is the response from listing templates.
576583
type TemplateListResponse struct {
577-
Templates []Template `json:"templates"`
584+
Templates []Template `json:"templates"`
585+
Categories []string `json:"categories,omitempty"`
578586
}
579587

580588
// TemplateDetailResponse is the response from getting a template.
581589
type TemplateDetailResponse struct {
582590
Template Template `json:"template"`
583591
}
584592

593+
// SubmitTemplateBody is the request body for validating, submitting, or updating a template.
594+
type SubmitTemplateBody struct {
595+
GitURL string `json:"gitUrl,omitempty"`
596+
Branch string `json:"branch,omitempty"`
597+
}
598+
599+
// ValidateTemplateResponse is the response from validating a git repo for template submission.
600+
type ValidateTemplateResponse struct {
601+
Valid bool `json:"valid"`
602+
Errors []string `json:"errors"`
603+
Manifest interface{} `json:"manifest,omitempty"`
604+
Readme string `json:"readme,omitempty"`
605+
Files []string `json:"files,omitempty"`
606+
CommitSha string `json:"commitSha,omitempty"`
607+
}
608+
609+
// SubmitTemplateResponse is the response from submitting or updating a template.
610+
type SubmitTemplateResponse struct {
611+
Success bool `json:"success"`
612+
Template Template `json:"template,omitempty"`
613+
Error string `json:"error,omitempty"`
614+
ValidationErrors []string `json:"validationErrors,omitempty"`
615+
}
616+
617+
// DeleteTemplateResponse is the response from deleting a template submission.
618+
type DeleteTemplateResponse struct {
619+
Success bool `json:"success"`
620+
Message string `json:"message,omitempty"`
621+
}
622+
623+
// BranchesBody is the request body for listing branches.
624+
type BranchesBody struct {
625+
GitURL string `json:"gitUrl"`
626+
}
627+
628+
// BranchesResponse is the response from listing branches.
629+
type BranchesResponse struct {
630+
Branches []string `json:"branches"`
631+
}
632+
585633
// --- Config ---
586634

587635
// ConfigResponse is the response from getting agent config.

0 commit comments

Comments
 (0)