### Subprocess Usage Example
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Demonstrates starting a subprocess with optional callbacks for stdout and stderr, and alternatively, connecting to the 'stdout' and 'stderr' signals.
```typescript
const proc = subprocess(
"some-command",
(out) => console.log(out), // optional
(err) => console.error(err), // optional
)
// or with signals
const proc = subprocess("some-command")
proc.connect("stdout", (_, out) => console.log(out))
proc.connect("stderr", (_, err) => console.error(err))
```
--------------------------------
### CLI Instance Name Examples
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Examples showing how to specify the instance name using the CLI, both for older and newer versions.
```sh
ags -i name
```
```sh
ags -t window-name -i name
```
```sh
ags run
```
```sh
ags toggle window-name -i name
```
--------------------------------
### Example App Implementation
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
A full example of a Gtk.Application subclass that handles command-line arguments and creates a main window.
```tsx
import Astal from "gi://Astal?version=4.0"
import Gio from "gi://Gio?version=2.0"
import GObject from "gi://GObject?version=2.0"
import Gtk from "gi://Gtk?version=4.0"
import { programInvocationName, programArgs } from "system"
import { createRoot } from "gnim"
class App extends Gtk.Application {
static {
GObject.registerClass(this)
}
constructor() {
super({
applicationId: "my.awesome.app",
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
})
}
vfunc_command_line(cmd: Gio.ApplicationCommandLine): number {
const args: string[] = cmd.get_arguments()
if (cmd.isRemote) {
console.log("invoked from remote instance")
cmd.print_literal("hello from primary instance")
cmd.done()
} else {
this.main(args)
}
return 0
}
private main(args: string[]) {
createRoot((dispose) => {
this.connect("shutdown", dispose)
return (
)
})
}
}
const app = new App()
app.runAsync([programInvocationName, ...programArgs])
```
--------------------------------
### Update Syntax for Button Setup
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
The 'setup' function is now represented by '$', and 'className' has been changed to 'class'.
```tsx
print("ref", self)} />
```
--------------------------------
### CLI Request Example
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Example of sending a request to the application from the CLI and receiving a response.
```sh
ags request say hi
# hi
```
--------------------------------
### CLI Request Execution Examples
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Examples demonstrating how to execute JavaScript functions via the CLI using the new request system.
```sh
ags -r "myfunction()"
```
```sh
ags request myfunction
```
--------------------------------
### Build and Install AGS from Source
Source: https://github.com/aylur/ags/blob/main/docs/guide/install.md
Clones the AGS repository, installs Node.js dependencies, and builds using Meson.
```sh
git clone https://github.com/aylur/ags.git
cd ags
npm install
meson setup build
meson install -C build
```
--------------------------------
### Install AGS on Arch Linux
Source: https://github.com/aylur/ags/blob/main/docs/guide/install.md
Use the `yay` AUR helper to install the `aylurs-gtk-shell-git` package.
```sh
yay -S aylurs-gtk-gtk-shell-git
```
--------------------------------
### AGS `app` Instance Methods for Runtime Management
Source: https://context7.com/aylur/ags/llms.txt
Manage windows, themes, CSS, and icons at runtime using methods on the `app` singleton. Includes functions for getting windows, toggling visibility, applying/resetting CSS, and adding icon paths.
```ts
import app from "ags/gtk4/app"
// Get a window by its name property
const bar = app.get_window("Bar")
if (bar) bar.visible = true
// Toggle a window's visibility
app.toggle_window("Bar")
// Apply CSS (string or path to file)
app.apply_css("/path/to/style.css")
app.apply_css(`button { color: red; }`)
// Reset all applied CSS providers
app.reset_css()
// Add a directory to the icon theme search path
app.add_icons("/path/to/icons/hicolor")
// List all Gdk.Monitor objects
const monitors = app.get_monitors()
// or via property
const mons = app.monitors
// Set themes
app.gtkTheme = "Adwaita-dark"
app.iconTheme = "Papirus"
app.cursorTheme = "Bibata-Modern-Ice"
// Quit with optional exit code
app.quit(0)
```
--------------------------------
### Timer Usage Example
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Demonstrates creating an interval timer, connecting to its 'now' and 'cancelled' signals, and cancelling it.
```typescript
const timer = interval(1000, () => {
console.log("optional callback")
})
timer.connect("now", () => {
console.log("tick")
})
timer.connect("cancelled", () => {
console.log("cancelled")
})
timer.cancel()
```
--------------------------------
### Install AGS Dependencies on Fedora
Source: https://github.com/aylur/ags/blob/main/docs/guide/install.md
Installs necessary development packages for AGS on Fedora using dnf.
```sh
sudo dnf install \
npm meson ninja golang gobject-introspection-devel \
gtk3-devel gtk-layer-shell-devel \
gtk4-devel gtk4-layer-shell-devel
```
--------------------------------
### Nix Flake for AGS Project Setup
Source: https://context7.com/aylur/ags/llms.txt
Define a Nix flake to build a development shell with necessary packages and the AGS framework. This setup includes `wrapGAppsHook3` for GTK applications and `gobject-introspection` for GObject bindings.
```nix
# flake.nix — Build a shell as a Nix derivation
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
astal.url = "github:aylur/astal";
ags.url = "github:aylur/ags";
};
outputs = { self, nixpkgs, ags, astal }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = pkgs.stdenv.mkDerivation {
pname = "my-shell";
src = ./.;
nativeBuildInputs = [ pkgs.wrapGAppsHook3 pkgs.gobject-introspection
ags.packages.${system}.default ];
buildInputs = [ pkgs.glib pkgs.gjs astal.io astal.astal4
astal.packages.${system}.battery ];
installPhase = "ags bundle app.ts $out/bin/my-shell";
};
};
}
```
--------------------------------
### Get and Toggle Window in JavaScript
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Get a window instance by its name in JavaScript and control its visibility.
```ts
const bar = app.get_window("Bar")
if (bar) bar.visible = true
```
--------------------------------
### Install AGS Dependencies on Arch Linux
Source: https://github.com/aylur/ags/blob/main/docs/guide/install.md
Installs necessary development packages for AGS on Arch Linux using pacman.
```sh
sudo pacman -Syu \
npm meson ninja go gobject-introspection \
gtk3 gtk-layer-shell \
gtk4 gtk4-layer-shell
```
--------------------------------
### Import Process Utilities
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Import functions for managing subprocesses, including starting, executing, and creating them.
```typescript
import { subprocess, exec, execAsync, createSubprocess } from "ags/process"
```
--------------------------------
### Define Custom Instance Name
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Start the application with a custom instance name to allow multiple instances to run concurrently.
```ts
app.start({
instanceName: "my-instance", // defaults to "ags"
main() {}
})
```
--------------------------------
### createSubprocess
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Creates a signal that manages a subprocess, starting it when the first subscriber appears and killing it when subscribers drop to zero.
```APIDOC
## createSubprocess
### Description
Creates a signal that starts a subprocess when the first subscriber appears and kills the subprocess when the number of subscribers drops to zero.
### Signatures
`export function createSubprocess(init: string, exec: string | string[]): Accessor`
`export function createSubprocess(init: T, exec: string | string[], transform: (stdout: string, prev: T) => T): Accessor`
### Example
```tsx
function Log() {
const log = createSubprocess("", "journalctl -f")
return
}
```
```
--------------------------------
### Create Poll Usage Example
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Example of using createPoll to create a reactive counter that increments every second.
```tsx
function Counter() {
const counter = createPoll(0, 1000, (prev) => prev + 1)
return c.toString())} />
}
```
--------------------------------
### Advanced Event Handling with EventControllers
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Provides an example of using `Gtk.GestureClick` for more complex event handling scenarios in Gtk4, demonstrating how to capture specific click events.
```tsx
print("clicked with primary button")}
/>
```
--------------------------------
### Nix Flake Configuration for AGS Bundle
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This Nix flake configuration defines a derivation for building the AGS project. It includes necessary inputs like nixpkgs, astal, and ags, and sets up the build process using `stdenv.mkDerivation` with `ags bundle` for the install phase.
```nix
{ inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
astal = {
url = "github:aylur/astal";
inputs.nixpkgs.follows = "nixpkgs";
};
ags = {
url = "github:aylur/ags";
inputs.nixpkgs.follows = "nixpkgs";
inputs.astal.follows = "astal";
};
};
outputs = { self, nixpkgs, ags, astal }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = pkgs.stdenv.mkDerivation { # [!code focus:31]
pname = "my-shell";
src = ./.;
nativeBuildInputs = with pkgs;
[ wrapGAppsHook3
gobject-introspection
ags.packages.${system}.default
];
buildInputs = [ pkgs.glib pkgs.gjs astal.io astal.astal4 # packages like astal.battery or pkgs.libsoup_4
];
installPhase = ''
ags bundle app.ts $out/bin/my-shell
'';
preFixup = ''
gappsWrapperArgs+=( --prefix PATH : ${pkgs.lib.makeBinPath ([ # runtime executables ])} )
'';
};
};
}
```
--------------------------------
### Make HTTP Requests with fetch
Source: https://context7.com/aylur/ags/llms.txt
Use the `fetch` function for making HTTP requests. Supports GET and POST with JSON bodies. Ensure `ags/fetch` is imported.
```typescript
import { fetch, URL } from "ags/fetch"
// GET request
const res = await fetch("https://wttr.in/?format=3")
const text = await res.text()
console.log(text) // "City: ⛅ +18°C"
// POST with JSON body
const url = new URL("https://api.example.com/status")
url.searchParams.set("v", "2")
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: "hello" }),
})
if (response.ok) {
const data = await response.json()
console.log(data)
} else {
console.error("HTTP error", response.status)
}
```
--------------------------------
### Create Subprocess with Lifecycle Management
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
The `createSubprocess` function starts a subprocess when the first subscriber appears and kills it when subscribers drop to zero. It can optionally transform the stdout.
```ts
export function createSubprocess(
init: string,
exec: string | string[],
): Accessor
export function createSubprocess(
init: T,
exec: string | string[],
transform: (stdout: string, prev: T) => T,
): Accessor
```
```tsx
function Log() {
const log = createSubprocess("", "journalctl -f")
return
}
```
--------------------------------
### Bundle AGS Project with `ags bundle`
Source: https://context7.com/aylur/ags/llms.txt
Bundle a project into a single self-contained GJS executable script for distribution or packaging. Useful for install phases in Nix derivations.
```sh
# Bundle app.ts into an output binary
ags bundle app.ts /usr/local/bin/my-shell
```
```sh
# Used inside a Nix derivation installPhase:
ags bundle app.ts $out/bin/my-shell
```
--------------------------------
### Register Keybindings for GTK3 Window
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Set the keymode to ON_DEMAND to make a GTK3 window focusable and capture key press events. This example shows how to close the window when the Escape key is pressed.
```tsx
{
if (event.get_keyval()[1] === Gdk.KEY_Escape) {
self.hide()
}
}}
/>
```
--------------------------------
### app.start() — Application Entry Point
Source: https://context7.com/aylur/ags/llms.txt
The `app.start()` method is the entry point for initializing the Gtk.Application instance. Its `main` callback is executed once when the application launches.
```APIDOC
## `app.start()` — Application Entry Point
`app` is the singleton `Gtk.Application` instance exported from `ags/gtk4/app` (or `ags/gtk3/app`). All initialization happens inside `app.start()`'s `main` callback, which is run once when the application launches.
```tsx
import app from "ags/gtk4/app"
import { Astal } from "ags/gtk4"
import { createPoll } from "ags/time"
app.start({
instanceName: "my-shell", // DBus name becomes io.Astal.my-shell
css: `window { background: transparent; }`,
icons: `${import.meta.dir}/icons`,
gtkTheme: "Adwaita-dark",
requestHandler(argv, response) {
const [cmd, ...args] = argv
if (cmd === "hello") return response(`Hello, ${args[0]}!`)
response("unknown command")
},
main() {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
const clock = createPoll("", 1000, () => new Date().toLocaleTimeString())
return (
)
},
})
```
```
--------------------------------
### AGS Application Entry Point with `app.start()`
Source: https://context7.com/aylur/ags/llms.txt
Initialize the Gtk.Application instance and define application lifecycle callbacks. Configure instance name, CSS, icons, GTK theme, and request handlers.
```tsx
import app from "ags/gtk4/app"
import { Astal } from "ags/gtk4"
import { createPoll } from "ags/time"
app.start({
instanceName: "my-shell", // DBus name becomes io.Astal.my-shell
css: `window { background: transparent; }`,
icons: `${import.meta.dir}/icons`,
gtkTheme: "Adwaita-dark",
requestHandler(argv, response) {
const [cmd, ...args] = argv
if (cmd === "hello") return response(`Hello, ${args[0]}!`)
response("unknown command")
},
main() {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
const clock = createPoll("", 1000, () => new Date().toLocaleTimeString())
return (
)
},
})
```
--------------------------------
### Main Instance Execution
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
The `main` block of `app.start()` executes on the first invocation. Subsequent invocations act as client requests.
```ts
app.start({
requestHandler(argv, response) {
console.log("request", ...argv)
response("hello from main instance")
},
main(...argv: string[]) {
console.log(...argv)
},
})
```
--------------------------------
### app Instance Methods
Source: https://context7.com/aylur/ags/llms.txt
Methods on the `app` singleton for managing windows, themes, CSS, and icons at runtime.
```APIDOC
## `app` Instance Methods
Methods on the `app` singleton for managing windows, themes, CSS, and icons at runtime.
```ts
import app from "ags/gtk4/app"
// Get a window by its name property
const bar = app.get_window("Bar")
if (bar) bar.visible = true
// Toggle a window's visibility
app.toggle_window("Bar")
// Apply CSS (string or path to file)
app.apply_css("/path/to/style.css")
app.apply_css(`button { color: red; }`)
// Reset all applied CSS providers
app.reset_css()
// Add a directory to the icon theme search path
app.add_icons("/path/to/icons/hicolor")
// List all Gdk.Monitor objects
const monitors = app.get_monitors()
// or via property
const mons = app.monitors
// Set themes
app.gtkTheme = "Adwaita-dark"
app.iconTheme = "Papirus"
app.cursorTheme = "Bibata-Modern-Ice"
// Quit with optional exit code
app.quit(0)
```
```
--------------------------------
### Expose Astal CLI Tools with Home-Manager
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This configuration snippet for home.nix demonstrates how to expose Astal CLI tools, such as `notifd`, to your home environment by adding them to `home.packages`.
```nix
home.packages = [ inputs.astal.packages.${pkgs.system}.notifd ];
```
--------------------------------
### Initialize AGS project from template
Source: https://github.com/aylur/ags/blob/main/docs/guide/quick-start.md
Use the `ags init` command to set up a new project with necessary files for TypeScript development. This command automates the creation of a basic project structure.
```sh
ags init -d /path/to/project
```
--------------------------------
### Update Entry Point from App.config to app.start
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
The entry point configuration has changed from 'App.config' to 'app.start'. Specify the main file as an argument to 'ags run' or name it 'app.js'/'app.ts' etc. for default usage.
```javascript
App.config({
windows: [
// window instances
],
})
```
```javascript
import app from "astal/gtk4/app"
app.start({
main() {
// any initialization code
},
})
```
--------------------------------
### Application Entry Point
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Defines the main entry point for an application using `app.start`. The `main` function is where widgets are instantiated.
```typescript
import app from "ags/gtk4/app"
app.start({
main() {
// you will instantiate Widgets here
// and setup anything else if you need
},
})
```
--------------------------------
### Gtk4 CenterBox Element
Source: https://github.com/aylur/ags/blob/main/docs/guide/intrinsics.md
Utilize the `` element for Gtk4 to arrange child elements in start, center, and end positions.
```tsx
```
--------------------------------
### Import App Instance
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Import the `app` instance. The import path differs based on the Gtk version.
```ts
import app from "astal/gtk3/app"
import app from "astal/gtk4/app"
```
--------------------------------
### Creating a Custom Button Widget
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Defines a custom widget `MyButton` using JSX. Custom widgets are defined as functions starting with a capital letter.
```tsx
function MyButton() {
return (
console.log(self, "clicked")}>
)
}
```
--------------------------------
### Create a Basic Window with a Counter and Date
Source: https://github.com/aylur/ags/blob/main/docs/index.md
This snippet demonstrates creating a window with a centered layout, displaying the current date and time, and a button to increment a counter. It utilizes state management and polling for updates.
```tsx
function Bar() {
const [counter, setCounter] = createState(0)
const date = createPoll("", 1000, `date \"+%H:%M - %A %e.\"`)
return (
setCounter((c) => c + 1)}>
`clicked ${c} times`)} />
)
}
```
--------------------------------
### Run AGS with Nix
Source: https://github.com/aylur/ags/blob/main/docs/guide/install.md
Enter a Nix shell environment with AGS available directly from its GitHub repository.
```sh
nix shell github:aylur/ags
```
--------------------------------
### Import Utility Functions from Modules
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Utility functions like `exec`, `readFile`, `timeout`, and `fetch` are now available from dedicated modules.
```js
Utils.exec("command") // [!code --:4]
Utils.readFile("file")
Utils.timeout(1000, callback)
Utils.fetch("url")
```
```js
import { exec } from "ags/process"
import { readFile } from "ags/file"
import { timeout } from "ags/time"
import { fetch } from "ags/fetch"
```
--------------------------------
### Interactive Slider Input
Source: https://github.com/aylur/ags/blob/main/docs/guide/intrinsics.md
The Slider component provides a horizontal slider for input. It allows setting width and handling drag events to get the current value.
```tsx
print(value)} />
```
--------------------------------
### Add Custom SVG Symbolic Icons
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Shows how to add custom SVG symbolic icons by placing them in the correct directory structure and referencing them using `app.start` or `app.add_icons`.
```txt
.\n├── icons\n│ └── hicolor\n│ └── scalable\n│ └── actions\n│ └── custom-symbolic.svg\n└── app.ts
```
```ts
app.start({
icons: `${SRC}/icons`, // SRC will point to the root
main() {
new Gtk.Image({
iconName: "custom-symbolic",
})
},
})
```
--------------------------------
### State Management with GObject and createBinding
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Demonstrates state management by binding to GObject properties using createBinding and deriving values with createComputed. A custom GObject class 'CounterStore' is used to hold the state.
```tsx
import GObject, { register, property } from "ags/gobject"
import { createBinding, createComputed } from "ags"
@register()
class CounterStore extends GObject.Object {
@property(Number) count = 0
}
function Counter() {
const counter = new CounterStore()
function increment() {
counter.count += 1
}
const count = createBinding(count, "count")
const label = createComputed(() => count().toString())
return (
Click to increment
)
}
```
--------------------------------
### Create Persistent Floating Windows
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Demonstrates how to create regular floating windows using `Gtk.Window` and prevent them from being destroyed on close by handling the `delete-event`.
```tsx
return (
{
self.hide()
return true
}}
>
{child}
)
```
--------------------------------
### Conditionally Access Nested Objects with
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Use the component to conditionally render content based on the presence of nested reactive objects. This example binds a label to a nested value.
```tsx
function Component() {
const nested: Accessor = createBinding(object, "nested")
return (
{(nested) =>
nested && (
)
}
)
}
```
--------------------------------
### Initialize AGS Project with `ags init`
Source: https://context7.com/aylur/ags/llms.txt
Scaffold a new AGS project with a full TypeScript development environment. Can initialize in a specified directory or use a Nix flake template.
```sh
# Initialize a project at a given directory
ags init -d /path/to/my-shell
```
```sh
# Initialize using the Nix flake template
nix flake init --template github:aylur/ags
```
--------------------------------
### ags types
Source: https://context7.com/aylur/ags/llms.txt
Generate TypeScript type definitions from installed GObject Introspection (`.gir`) libraries so IDEs and the TypeScript compiler can provide correct types for GNOME APIs.
```APIDOC
## CLI — `ags types`
Generate TypeScript type definitions from installed GObject Introspection (`.gir`) libraries so IDEs and the TypeScript compiler can provide correct types for GNOME APIs.
```sh
# Generate types and write to project root
ags types -u -d /path/to/project/root
# Equivalent npm script (runs @ts-for-gir/cli)
npm run types
```
```
--------------------------------
### ags init
Source: https://context7.com/aylur/ags/llms.txt
Scaffold a new AGS project with a full TypeScript development environment, tsconfig, package.json, and sample widget templates.
```APIDOC
## CLI — `ags init`
Scaffold a new AGS project with a full TypeScript development environment, tsconfig, package.json, and sample widget templates.
```sh
# Initialize a project at a given directory
ags init -d /path/to/my-shell
# Initialize using the Nix flake template
nix flake init --template github:aylur/ags
```
```
--------------------------------
### Register Keybindings for GTK4 Window
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Use Gtk.EventControllerKey to handle key press events in a GTK4 window when its keymode is set to ON_DEMAND. This example closes the window on Escape key press.
```tsx
{
if (keyval === Gdk.KEY_Escape) {
widget.hide()
}
}}
/>
```
--------------------------------
### Toggle Windows via CLI
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Previously, windows were passed as an array to `App.config`. Now, pass the `app` instance to `Window` to make windows toggleable by name through the CLI.
```javascript
App.config({
windows: [Widget.Window({ name: "window-name" })],
})
```
```javascript
app.start({
main() {
return
},
})
```
--------------------------------
### Initialize AGS project with Nix flake
Source: https://github.com/aylur/ags/blob/main/docs/guide/quick-start.md
Initialize an AGS project using a Nix flake template. This is an alternative method for setting up a development environment, particularly for users familiar with Nix.
```sh
nix flake init --template github:aylur/ags
```
--------------------------------
### State Management with createState
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Example of managing local state within a widget using createState for reactive values and createComputed for derived values. The increment function updates the state, and the label is derived from the count.
```tsx
import { createState, createComputed } from "ags"
function Counter() {
const [count, setCount] = createState(0)
function increment() {
setCount((v) => v + 1)
}
const label = createComputed(() => count().toString())
return (
Click to increment
)
}
```
--------------------------------
### Register Window with `application` Prop
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Register a window by passing the `app` instance to the `application` prop. Ensure the `name` prop is set before `application`.
```tsx
import app from "astal/gtk4/app"
function Bar() {
return (
)
}
```
--------------------------------
### Create Long-running Process Reactive Value with createSubprocess
Source: https://context7.com/aylur/ags/llms.txt
Use `createSubprocess` to create an Accessor backed by a persistent subprocess. The process starts on the first subscriber and is killed when the last disconnects. Output lines can directly become the accessor value or be transformed.
```tsx
import { createSubprocess } from "ags/process"
function JournalLog() {
// stdout lines become the accessor value
const log = createSubprocess("", "journalctl -f")
return
}
function NetworkSpeed() {
// Transform the raw output into a typed value
const speed = createSubprocess(
{ rx: 0, tx: 0 },
["bash", "-c", "while true; do cat /proc/net/dev; sleep 1; done"],
(stdout, prev) => {
const match = stdout.match(/eth0:\s+(\d+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\d+)/)
if (!match) return prev
return { rx: parseInt(match[1]), tx: parseInt(match[2]) }
},
)
return `↓${rx} ↑${tx}`)} />
}
```
--------------------------------
### Import and Bind Services
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Services are no longer imported via `Service.import`. Import them directly from their respective libraries and use `createBinding` for property binding.
```js
// importing
const battery = await Service.import("battery") // [!code --]
import Battery from "gi://AstalBattery"
const battery = Battery.get_default()
// binding
const b = battery.bind("percentage") // [!code --]
import { createBinding } from "ags"
const b = createBinding(battery, "percentage")
```
--------------------------------
### Root Widget: Window
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Illustrates the creation of a root `Window` widget, which is the top-level component of a desktop shell. Remember to explicitly set `visible` as windows are not visible by default.
```tsx
function Bar(monitor = 0) {
return (
Content of the widget
)
}
app.start({
main() {
Bar(0)
Bar(1) // instantiate for each monitor
},
})
```
--------------------------------
### Auto-Create Windows for Each Monitor
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Employs the `` component to dynamically create and manage top-level widgets for each available monitor.
```tsx
import Gtk from "gi://Gtk"
import Bar from "./Bar"
import { For, This, createBinding } from "ags"
function main() {
const monitors = createBinding(app, "monitors")
return (
{(monitor) => (
onCleanup(() => self.destroy())}
/>
{otherWindows}
)}
)
}
app.start({ main })
```
--------------------------------
### Create a Media Player Button List
Source: https://github.com/aylur/ags/blob/main/docs/index.md
This snippet demonstrates how to display a list of media players, with each player represented by a button. Clicking a button toggles the play/pause state of the corresponding player.
```tsx
function MediaPlayers() {
const players = createBinding(Mpris.get_default(), "players")
return (
{(player) => (
player.play_pause()}
/>
)}
)
}
```
--------------------------------
### Define Custom Services with GObject.Object
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Custom services are now created by subclassing `GObject.Object` and using decorators for properties and signals.
```ts
// [!code --:16]
class MyService extends Service {
static {
Service.register(
this,
{
"my-signal": ["float"],
},
{
"my-value": ["float", "rw"],
},
)
}
get my_value(): number
set my_value(v: number)
}
```
```ts
import GObject, { register, signal, property } from "ags/gobject"
@register()
class MyService extends GObject.Object {
@property(Number)
myValue = 0
@signal(Number)
mySignal(n: number): void {}
}
```
--------------------------------
### Instantiate Widgets in Main or Client Blocks
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
Avoid top-level widget instantiation. Use `main` or `client` blocks for script execution.
```js
const win = Widget.Window()
App.config({
windows: [win],
})
```
```js
app.main({
main() {
new Widget.Window()
},
})
```
--------------------------------
### Enter Nix Shell with AGS Full Package
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This command allows you to enter a Nix shell that includes the AGS package along with all Astal libraries, providing a comprehensive development environment.
```sh
nix shell github:aylur/ags#agsFull
```
--------------------------------
### Home-Manager Configuration for AGS
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This home.nix configuration enables the AGS program, sets its configuration directory, and includes additional packages and executables for the GJS runtime, such as Astal libraries and fzf.
```nix
{ inputs, pkgs }:
{
# add the home manager module
imports = [ inputs.ags.homeManagerModules.default ];
programs.ags = {
enable = true;
# symlink to ~/.config/ags
configDir = ../ags;
# additional packages and executables to add to gjs's runtime
extraPackages = with pkgs;
[ inputs.astal.packages.${pkgs.system}.battery fzf ];
};
}
```
--------------------------------
### Create Widget Components with JSX
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Wraps Gtk/Astal widgets in functions to achieve a cleaner syntax, similar to AGSv1.
```ts
import { CCProps, jsx } from "ags"
import { Gtk, Astal } from "ags/gtk4"
const Box = (props: Partial>) =>
jsx(Gtk.Box, props)
const Window = (
props: Partial>,
) => jsx(Astal.Window, props)
function Bar() {
return Window({
name: "Bar",
children: [Box({ children: ["Hello There"] })],
})
}
```
--------------------------------
### Register Window with `app.add_window`
Source: https://github.com/aylur/ags/blob/main/docs/guide/app-cli.md
Register a window with a unique name using `app.add_window()` for CLI control. The `name` prop must come before the `application` prop.
```tsx
import app from "astal/gtk4/app"
function Bar() {
return (
app.add_window(self)}>
)
}
```
--------------------------------
### Execute Shell Commands Safely
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Demonstrates the correct way to read environment variables using GLib.getenv, as direct execution of shell variables in `exec` is not supported.
```ts
const HOME = exec("echo $HOME") // does not work as you'd expect
```
```ts
const HOME = exec("bash -c 'echo $HOME'")
```
```ts
import GLib from "gi://GLib"
const HOME = GLib.getenv("HOME")
```
--------------------------------
### Nix Flake Configuration for Home-Manager Integration
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This Nix flake configuration sets up home-manager, allowing for the integration of AGS and other modules into your user environment. It specifies inputs for nixpkgs, home-manager, astal, and ags, and configures home-manager to import your user-specific configuration.
```nix
{ inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
astal.url = "github:aylur/astal";
ags.url = "github:aylur/ags"; # [!code focus]
};
outputs = { home-manager, nixpkgs, ... }@inputs:
let
system = "x86_64-linux";
in
{
homeConfigurations."${username}" = home-manager.lib.homeManagerConfiguration {
pkgs = import nixpkgs { inherit system; };
# pass inputs as specialArgs # [!code focus:2]
extraSpecialArgs = { inherit inputs; };
# import your home.nix # [!code focus:2]
modules = [ ./home-manager/home.nix ];
};
};
}
```
--------------------------------
### Define Instance Name in Code
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
The instance name is now defined within the code using `instanceName` in `app.start`, instead of being set via the CLI on first launch.
```javascript
app.start({
instanceName: "name",
})
```
--------------------------------
### Import File Utilities
Source: https://github.com/aylur/ags/blob/main/docs/guide/utilities.md
Import functions for reading and writing files asynchronously or synchronously.
```typescript
import { readFile, readFileAsync } from "ags/file"
function readFile(path: string): string
function readFileAsync(path: string): Promise
```
```typescript
import { writeFile, writeFileAsync } from "ags/file"
function writeFile(path: string, content: string): void
function writeFileAsync(path: string, content: string): Promise
```
--------------------------------
### Astal Window Element (Gtk4)
Source: https://github.com/aylur/ags/blob/main/docs/guide/intrinsics.md
Configure Gtk4 windows using the `` element from Astal, specifying visibility, namespace, class, monitor, exclusivity, keymode, and anchor.
```tsx
```
--------------------------------
### Schedule Callbacks with Timer Utilities
Source: https://context7.com/aylur/ags/llms.txt
Utilities for scheduling callbacks using GLib-backed timers. `interval` fires repeatedly, `timeout` fires once after a delay, and `idle` fires when the event loop is idle. All return a `Timer` instance with `cancel()` and signals.
```ts
import { interval, timeout, idle } from "ags/time"
// Fires immediately, then every 500ms
const ticker = interval(500, () => console.log("tick"))
ticker.connect("now", () => {
// runs on every tick
})
ticker.connect("cancelled", () => {
console.log("timer stopped")
})
// Cancel after 5 seconds
timeout(5000, () => ticker.cancel())
// Runs once after 1 second
timeout(1000, () => console.log("delayed once"))
// Runs when the event loop is idle
idle(() => console.log("idle callback"))
```
--------------------------------
### Run a single-file AGS bar with TypeScript
Source: https://github.com/aylur/ags/blob/main/docs/guide/quick-start.md
Create a simple bar using TypeScript and run it directly with the `ags run` command. This is useful for quick prototyping.
```tsx
import app from "ags/gtk4/app"
import { Astal } from "ags/gtk4"
import { createPoll } from "ags/time"
app.start({
main() {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
const clock = createPoll("", 1000, "date")
return (
)
},
})
```
--------------------------------
### ags run
Source: https://context7.com/aylur/ags/llms.txt
Run a TypeScript/JSX entry file directly without a bundling step, using esbuild for transpilation.
```APIDOC
## CLI — `ags run`
Run a TypeScript/JSX entry file directly without a bundling step, using esbuild under the hood for transpilation.
```sh
# Run a single file
ags run ./app.tsx
# Run with a shebang (make file executable)
#!/usr/bin/env -S ags run
chmod +x app.tsx && ./app.tsx
# Run the default entry (app.ts / app.tsx) in ~/.config/ags
ags run
```
```
--------------------------------
### Use Gdk.Monitor for Window Placement
Source: https://github.com/aylur/ags/blob/main/docs/guide/faq.md
Replaces monitor IDs with Gdk.Monitor objects for accurate window placement, as Gdk monitor IDs may differ from compositor IDs.
```tsx
function Bar(gdkmonitor) {
return
}
function main() {
for (const monitor of app.get_monitors()) {
if (monitor.model == "your-desired-model") {
Bar(monitor)
}
}
}
```
--------------------------------
### Execute Commands with subprocess, exec, execAsync
Source: https://context7.com/aylur/ags/llms.txt
Utilities for spawning subprocesses and executing commands. `exec` is synchronous and blocks the event loop, while `execAsync` is asynchronous and preferred. `subprocess` allows for long-lived processes with stdout/stderr callbacks.
```ts
import { subprocess, exec, execAsync } from "ags/process"
// Long-lived subprocess with stdout/stderr callbacks
const proc = subprocess(
"pactl subscribe",
(out) => console.log("pactl:", out),
(err) => console.error("pactl error:", err),
)
// Write to stdin
proc.write("command\n")
// Kill when done
proc.kill()
// Signal-based API
const proc2 = subprocess("some-command")
proc2.connect("stdout", (_, line) => console.log(line))
proc2.connect("stderr", (_, err) => console.error(err))
proc2.connect("exit", (_, code, signaled) => console.log("exit", code))
// Synchronous execution (blocks the event loop — use sparingly)
try {
const out = exec("playerctl status")
console.log(out) // "Playing"
} catch (err) {
console.error(err)
}
// Async execution (preferred)
execAsync(["nmcli", "d", "wifi", "connect", "MySSID"])
.then((out) => console.log(out))
.catch((err) => console.error(err))
// Using bash for shell features / env vars
execAsync(["bash", "-c", "echo $HOME && ls -la"])
.then(console.log)
```
--------------------------------
### Display Help for Astal Notifd CLI
Source: https://github.com/aylur/ags/blob/main/docs/guide/nix.md
This command shows the help message for the `astal-notifd` command-line tool, providing information on its usage and available options.
```sh
astal-notifd --help
```
--------------------------------
### Perform File I/O with File Utilities
Source: https://context7.com/aylur/ags/llms.txt
Utilities for synchronous and asynchronous file operations, including reading, writing, and monitoring files or directories. `monitorFile` uses `Gio.FileMonitor` for recursive monitoring.
```ts
import { readFile, readFileAsync, writeFile, writeFileAsync, monitorFile } from "ags/file"
import Gio from "gi://Gio"
// Synchronous read
const content = readFile("/etc/hostname")
console.log(content.trim())
// Async read
readFileAsync("/home/user/.config/ags/config.json")
.then((json) => console.log(JSON.parse(json)))
.catch((err) => console.error(err))
// Synchronous write (creates parent dirs automatically)
writeFile("/tmp/ags-test.txt", "hello from AGS")
// Async write
await writeFileAsync("/tmp/ags-async.txt", JSON.stringify({ ok: true }))
// Monitor a file or directory for changes
const monitor = monitorFile("/home/user/.config/ags", (path, event) => {
if (event === Gio.FileMonitorEvent.CHANGED) {
console.log("changed:", path)
}
if (event === Gio.FileMonitorEvent.DELETED) {
console.log("deleted:", path)
}
})
// Cancel monitoring
monitor.cancel()
```
--------------------------------
### Home Manager Module for AGS Configuration
Source: https://context7.com/aylur/ags/llms.txt
Configure AGS declaratively using Home Manager on NixOS. This module enables AGS, sets the configuration directory, and includes extra Astal packages for system integration.
```nix
# home.nix — Home Manager module
{
imports = [ inputs.ags.homeManagerModules.default ];
programs.ags = {
enable = true;
configDir = ../ags; # symlinked to ~/.config/ags
extraPackages = with inputs.astal.packages.${pkgs.system};
[ battery
network
wireplumber
tray
mpris
];
};
}
```
--------------------------------
### CLI Requests for JavaScript Execution
Source: https://github.com/aylur/ags/blob/main/docs/guide/migration-guide.md
The `ags --run-js` command has been removed. Use the `requestHandler` in `app.start` to handle requests from the CLI.
```typescript
globalThis.myfunction = () => {
print("hello")
}
```
```typescript
app.start({
requestHandler(request: string, res: (response: any) => void) {
if (request == "myfunction") {
res("hello")
}
res("unknown command")
},
})
```
--------------------------------
### Rendering Lists of Widgets
Source: https://github.com/aylur/ags/blob/main/docs/guide/first-widgets.md
Explains how to render lists of widgets by iterating over JavaScript arrays using methods like `map()`. Each item in the list is rendered as a widget.
```tsx
function MyWidget() {
const labels = ["label1", "label2", "label3"]
return (
{labels.map((label) => (
))}
)
}
```
--------------------------------
### Window Configuration
Source: https://github.com/aylur/ags/blob/main/docs/guide/intrinsics.md
The Window component configures top-level windows with properties like namespace, class, monitor, exclusivity, keymode, and anchor points.
```tsx
```
--------------------------------
### ags toggle, ags request, ags inspect
Source: https://context7.com/aylur/ags/llms.txt
Control a running AGS instance from the command line: toggle window visibility, send custom requests, or open the GTK inspector.
```APIDOC
## CLI — `ags toggle`, `ags request`, `ags inspect`
Control a running AGS instance from the command line: toggle window visibility, send custom requests, or open the GTK inspector.
```sh
# Toggle visibility of a named window
ags toggle Bar
# Toggle on a named instance
ags toggle Bar -i my-instance
# Send a custom request to the running instance
ags request say hello
# → hello
# Open GTK inspector for CSS/widget debugging
ags inspect
```
```