# Develop with Go (/en/ai/ten-agent/develop/develop-with-go)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

This guide shows you how to create and build Go applications using the TEN Framework's Go language binding.

This guide shows you how to create and build Go applications using the TEN Framework's Go language binding.

## Create a TEN Go application [#create-a-ten-go-application]

Create a new TEN application using Go with the following steps:

### Generate the application [#generate-the-application]

Use TEN Manager to create a new Go application from the default template:

```bash
tman create app my_go_app --template default_app_go
cd my_go_app
```

### Install dependencies [#install-dependencies]

Install the required TEN packages and extensions:

```bash
tman install protocol msgpack
tman install extension_group default_extension_group
tman install extension default_extension_go
```

### Install a default TEN extension [#install-a-default-ten-extension]

To install a default Go TEN extension:

```bash
tman install extension default_extension_go
```

### Configure auto-start graph [#configure-auto-start-graph]

Configure your application to automatically start the installed extensions by adding a predefined graph to the `property.json` file:

```json
"predefined_graphs": [
  {
    "name": "default",
    "auto_start": true,
    "nodes": [
      {
        "type": "extension_group",
        "name": "default_extension_group",
        "addon": "default_extension_group"
      },
      {
        "type": "extension",
        "name": "default_extension_go",
        "addon": "default_extension_go",
        "extension_group": "default_extension_group"
      }
    ]
  }
]
```

## Build the application [#build-the-application]

TEN Go applications require CGO integration, which needs specific environment variables and build configuration. Use the build script provided in the TEN runtime to handle these requirements automatically:

```bash
go run ten_packages/system/ten_runtime_go/tools/build/main.go
```

The build process creates a compiled binary named `main` in the `bin/` directory.

## Run the application [#run-the-application]

Use the provided start script to launch your application with the correct environment variables:

```bash
./bin/start
```

The start script automatically configures the necessary library paths and environment settings for the TEN runtime.

## Debug your application [#debug-your-application]

Set up debugging configurations for Visual Studio Code to debug both Go and C code in your TEN application.

### Go code debugging [#go-code-debugging]

Add this configuration to your `.vscode/launch.json` file to debug the Go portions of your application:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Go app (launch)",
      "type": "go",
      "request": "launch",
      "mode": "auto",
      "program": "${workspaceFolder}",
      "cwd": "${workspaceFolder}",
      "output": "${workspaceFolder}/bin/tmp",
      "env": {
        "LD_LIBRARY_PATH": "${workspaceFolder}/lib",
        "DYLD_LIBRARY_PATH": "${workspaceFolder}/lib",
        "CGO_LDFLAGS": "-L${workspaceFolder}/lib -lten_runtime_go -Wl,-rpath,@loader_path/lib"
      }
    }
  ]
}
```

### C code debugging [#c-code-debugging]

Add this configuration to your `.vscode/launch.json` file to debug the C/CGO portions of your application:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "C (launch)",
      "type": "lldb",
      "request": "launch",
      "program": "${workspaceFolder}/bin/main",
      "cwd": "${workspaceFolder}",
      "env": {
        "LD_LIBRARY_PATH": "${workspaceFolder}/lib",
        "DYLD_LIBRARY_PATH": "${workspaceFolder}/lib",
        "CGO_LDFLAGS": "-L${workspaceFolder}/lib -lten_runtime_go -Wl,-rpath,@loader_path/lib"
      }
    }
  ]
}
```

## CGO integration [#cgo-integration]

### Understand generated code [#understand-generated-code]

The TEN Framework's Go binding relies on CGO to interface between Go and C code. When you call C functions from Go, the `cgo` tool automatically converts your Go source files into multiple output files containing both Go and C code. These generated C files are then compiled using standard C compilers like `gcc` or `clang`.

You can manually generate and examine these intermediate files using:

```bash
mkdir out
go tool cgo -objdir out cmd.go error.go
```

This creates several generated files that bridge Go and C:

The CGO generation process creates several key files that enable Go-C interoperability:

```bash
├── _cgo_export.c
├── _cgo_export.h
├── _cgo_flags
├── _cgo_gotypes.go
├── _cgo_main.c
├── _cgo_.o
├── cmd.cgo1.go
├── cmd.cgo2.c
├── error.cgo1.go
└── error.cgo2.c
```

#### Key generated files [#key-generated-files]

* `_cgo_export.h`: Enables C code to call Go functions\
  Contains declarations for Go functions exported with the `//export` directive, plus C type definitions that correspond to Go types:

  ```cpp
  typedef signed char GoInt8;
  typedef unsigned char GoUint8;
  typedef short GoInt16;
  typedef unsigned short GoUint16;
  typedef int GoInt32;
  typedef unsigned int GoUint32;
  typedef long long GoInt64;
  typedef unsigned long long GoUint64;
  typedef GoInt64 GoInt;
  typedef GoUint64 GoUint;
  typedef size_t GoUintptr;
  typedef float GoFloat32;
  typedef double GoFloat64;
  ```

* `_cgo_gotypes.go`: Contains Go representations of C types\
  When you use C types like `C.ten_go_error_t` in Go, this file provides the corresponding Go struct definitions:

  ```go
  package ten

  type _Ctype_ten_go_status_t = _Ctype_struct_ten_go_status_t

  type _Ctype_struct_ten_go_status_t struct {
      err_no   _Ctype_int
      msg_size _Ctype_uint8_t
      err_msg  [256]_Ctype_char
      _        [3]byte
  }
  ```

* `cmd.cgo1.go`: Go wrapper for C function calls\
  Replaces direct C function calls with CGO-generated wrappers that handle type conversion and memory management:

  ```go
  package ten

  func NewCmd(cmdName string) (Cmd, error) {
      // ...
      cStatus := func() _Ctype_struct_ten_go_status_t {
          var _cgo0 _cgo_unsafe.Pointer = unsafe.Pointer(unsafe.StringData(cmdName))
          var _cgo1 _Ctype_int = _Ctype_int(len(cmdName))
          _cgoBase2 := &bridge
          _cgo2 := _cgoBase2
          _cgoCheckPointer(_cgoBase2, 0 == 0)
          return _Cfunc_ten_go_cmd_create_custom_cmd(_cgo0, _cgo1, _cgo2)
      }()
      // ...
  }
  ```

* `cmd.cgo2.c`: C wrapper for the actual C function\
  Provides the bridge between Go's calling convention and the native C function:

  ```cpp
  CGO_NO_SANITIZE_THREAD void _cgo_cb1b98e39356_Cfunc_ten_go_cmd_create_custom_cmd(void *v) {
      struct {
          const void* p0;
          int p1;
          char __pad12[4];
          ten_go_msg_t** p2;
          ten_go_error_t r;
      } __attribute__((__packed__, __gcc_struct__)) *_cgo_a = v;
      char *_cgo_stktop = _cgo_topofstack();
      __typeof__(_cgo_a->r) _cgo_r;
      _cgo_tsan_acquire();
      _cgo_r = ten_go_cmd_create_cmd(_cgo_a->p0, _cgo_a->p1, _cgo_a->p2);
      _cgo_tsan_release();
      _cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));
      _cgo_a->r = _cgo_r;
      _cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));
  }
  ```

#### Call sequence [#call-sequence]

When calling `C.ten_go_cmd_create_cmd()` from Go, the execution follows this path:

```text
_Cfunc_ten_go_cmd_create_custom_cmd (auto-generated Go)
           |
           V
   _cgo_runtime_cgocall (Go)
           |
           V
      entrysyscall     // switch Go stack to C stack
           |
           V
_cgo_cb1b98e39356_Cfunc_ten_go_cmd_create_custom_cmd (auto-generated C)
           |
           V
   ten_go_cmd_create_cmd (C)
           |
           V
      exitsyscall
```

### Work with incomplete types [#work-with-incomplete-types]

The `cgo` tool generates corresponding Go types based on C header files imported via `import "C"`. When a C struct is opaque (only declared, not defined), CGO creates an incomplete type in Go.

Example of an opaque C struct:

```cpp title="common.h"
typedef struct ten_go_msg_t ten_go_msg_t;
```

Generated incomplete type in Go:

```go title="_cgo_gotypes.go"
type _Ctype_ten_go_msg_t = _Ctype_struct_ten_go_msg_t
type _Ctype_struct_ten_go_msg_t _cgopackage.Incomplete
```

Incomplete types have the following limitations:

* **Cannot be allocated directly**\
  Go's garbage collector cannot manage incomplete types, so standard allocation fails:

  ```go
  msg := new(C.ten_go_msg_t) // Error: can't be allocated in Go; it is incomplete (or unallocatable)
  ```

* **Cannot pass pointers directly to C**\
  CGO rules require pointers to incomplete types to be "pinned" for garbage collector safety, making direct pointer passing impossible.

#### Workaround: Use `C.uintptr_t` [#workaround-use-cuintptr_t]

Instead of working with pointers to incomplete types, use `C.uintptr_t` to represent C pointers as integers.

This approach has the following benefits:

* **No allocation overhead**: `uintptr` values can be passed directly between Go and C
* **GC-safe**: No pointer tracking required since it's an integer value
* **Direct conversion**: Represents the exact memory address as an integer

#### Important limitations [#important-limitations]

* **No pointer arithmetic**: `uintptr` is just an integer representing an address
* **Cannot dereference**: Converting to `unsafe.Pointer` can break GC assumptions
* **Use `0` for null**: Since `uintptr` is an integer, use `0` instead of `nil` for null pointers

```go
// Correct way to represent a null pointer
var nullPtr C.uintptr_t = 0

// Incorrect - nil cannot be used with uintptr
// var badPtr C.uintptr_t = nil  // Compilation error
```
