diff --git a/pydra/engine/helpers.py b/pydra/engine/helpers.py
index 4835dfe9..1a441f1d 100644
--- a/pydra/engine/helpers.py
+++ b/pydra/engine/helpers.py
@@ -221,13 +221,29 @@ def make_klass(spec):
                 if isinstance(item[1], attr._make._CountingAttr):
                     newfields[item[0]] = item[1]
                 else:
-                    newfields[item[0]] = attr.ib(type=item[1])
+                    newfields[item[0]] = attr.ib(repr=False, type=item[1])
             else:
-                if isinstance(item[2], attr._make._CountingAttr):
-                    raise ValueError("Three part should not have attr")
-                    # newfields[item[0]] = item[2]
+                if (
+                    any([isinstance(ii, attr._make._CountingAttr) for ii in item])
+                    or len(item) > 4
+                ):
+                    raise ValueError(
+                        "syntax not valid, you can use (name, attr), "
+                        "(name, type, default), (name, type, default, metadata)"
+                        "or (name, type, metadata)"
+                    )
                 else:
-                    newfields[item[0]] = attr.ib(item[2], type=item[1])
+                    if len(item) == 3:
+                        name, tp = item[:2]
+                        if isinstance(item[-1], dict) and "help_string" in item[-1]:
+                            mdata = item[-1]
+                            newfields[name] = attr.ib(type=tp, metadata=mdata)
+                        else:
+                            dflt = item[-1]
+                            newfields[name] = attr.ib(type=tp, default=dflt)
+                    elif len(item) == 4:
+                        name, tp, dflt, mdata = item
+                        newfields[name] = attr.ib(type=tp, default=dflt, metadata=mdata)
         fields = newfields
     return attr.make_class(spec.name, fields, bases=spec.bases, kw_only=True)
 

Readable SpecInfos
The SpecInfo class is currently very inscrutable. An improved `__repr__` will be important for making development more friendly.
diff --git a/pydra/engine/tests/test_shelltask.py b/pydra/engine/tests/test_shelltask.py
index 5d291579..011e83c7 100644
--- a/pydra/engine/tests/test_shelltask.py
+++ b/pydra/engine/tests/test_shelltask.py
@@ -392,6 +392,32 @@ def test_shell_cmd_inputspec_3(plugin, results_function):
 @pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
 @pytest.mark.parametrize("plugin", Plugins)
 def test_shell_cmd_inputspec_3a(plugin, results_function):
+    """  mandatory field added to fields, value provided
+        using shorter syntax for input spec (no attr.ib)
+    """
+    cmd_exec = "echo"
+    hello = "HELLO"
+    my_input_spec = SpecInfo(
+        name="Input",
+        fields=[
+            ("text", str, {"position": 1, "help_string": "text", "mandatory": True})
+        ],
+        bases=(ShellSpec,),
+    )
+
+    # separate command into exec + args
+    shelly = ShellCommandTask(
+        name="shelly", executable=cmd_exec, text=hello, input_spec=my_input_spec
+    )
+    assert shelly.inputs.executable == cmd_exec
+    assert shelly.cmdline == "echo HELLO"
+    res = results_function(shelly, plugin)
+    assert res.output.stdout == "HELLO\n"
+
+
+@pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
+@pytest.mark.parametrize("plugin", Plugins)
+def test_shell_cmd_inputspec_3b(plugin, results_function):
     """  mandatory field added to fields, value provided after init"""
     cmd_exec = "echo"
     hello = "HELLO"
@@ -421,7 +447,7 @@ def test_shell_cmd_inputspec_3a(plugin, results_function):
 
 
 @pytest.mark.parametrize("plugin", Plugins)
-def test_shell_cmd_inputspec_3b_exception(plugin):
+def test_shell_cmd_inputspec_3c_exception(plugin):
     """  mandatory field added to fields, value is not provided, so exception is raised """
     cmd_exec = "echo"
     my_input_spec = SpecInfo(
@@ -511,6 +537,31 @@ def test_shell_cmd_inputspec_4(plugin, results_function):
 @pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
 @pytest.mark.parametrize("plugin", Plugins)
 def test_shell_cmd_inputspec_4a(plugin, results_function):
+    """  mandatory field added to fields, value provided
+        using shorter syntax for input spec (no attr.ib)
+    """
+    cmd_exec = "echo"
+    my_input_spec = SpecInfo(
+        name="Input",
+        fields=[("text", str, "Hello", {"position": 1, "help_string": "text"})],
+        bases=(ShellSpec,),
+    )
+
+    # separate command into exec + args
+    shelly = ShellCommandTask(
+        name="shelly", executable=cmd_exec, input_spec=my_input_spec
+    )
+
+    assert shelly.inputs.executable == cmd_exec
+    assert shelly.cmdline == "echo Hello"
+
+    res = results_function(shelly, plugin)
+    assert res.output.stdout == "Hello\n"
+
+
+@pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
+@pytest.mark.parametrize("plugin", Plugins)
+def test_shell_cmd_inputspec_4b(plugin, results_function):
     """  mandatory field added to fields, value provided """
     cmd_exec = "echo"
     my_input_spec = SpecInfo(
@@ -1170,6 +1221,33 @@ def test_shell_cmd_inputspec_state_1(plugin, results_function):
     assert res[1].output.stdout == "hi\n"
 
 
+@pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
+@pytest.mark.parametrize("plugin", Plugins)
+def test_shell_cmd_inputspec_state_1a(plugin, results_function):
+    """  adding state to the input from input_spec
+        using shorter syntax for input_spec (without default)
+    """
+    cmd_exec = "echo"
+    hello = ["HELLO", "hi"]
+    my_input_spec = SpecInfo(
+        name="Input",
+        fields=[
+            ("text", str, {"position": 1, "help_string": "text", "mandatory": True})
+        ],
+        bases=(ShellSpec,),
+    )
+
+    # separate command into exec + args
+    shelly = ShellCommandTask(
+        name="shelly", executable=cmd_exec, text=hello, input_spec=my_input_spec
+    ).split("text")
+    assert shelly.inputs.executable == cmd_exec
+
+    res = results_function(shelly, plugin)
+    assert res[0].output.stdout == "HELLO\n"
+    assert res[1].output.stdout == "hi\n"
+
+
 @pytest.mark.parametrize("results_function", [result_no_submitter, result_submitter])
 @pytest.mark.parametrize("plugin", Plugins)
 def test_shell_cmd_inputspec_state_2(plugin, results_function):

pip install -e .[dev]
parse_log_pytest
pytest
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asttokens==3.0.0
attrs==25.3.0
beautifulsoup4==4.13.3
black==25.1.0
bleach==6.2.0
cachetools==5.5.2
certifi==2025.1.31
cfgv==3.4.0
charset-normalizer==3.4.1
ci-info==0.3.0
click==8.1.8
cloudpickle==3.1.1
codecov==2.1.13
comm==0.2.2
coverage==7.8.0
debugpy==1.8.13
decorator==5.2.1
defusedxml==0.7.1
distlib==0.3.9
entrypoints==0.4
etelemetry==0.3.1
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
execnet==2.1.1
executing==2.2.0
fastjsonschema==2.21.1
filelock==3.18.0
frozendict==2.4.6
identify==2.6.9
idna==3.10
importlib_metadata==8.6.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
ipykernel==6.9.2
ipython==8.18.1
ipython-genutils==0.2.0
ipywidgets==8.1.5
jedi==0.19.2
Jinja2==3.1.6
json5==0.10.0
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
jupyter==1.1.1
jupyter-client==7.1.2
jupyter-console==6.4.4
jupyter-contrib-nbextensions==0.5.1
jupyter-highlight-selected-word==0.2.0
jupyter_contrib_core==0.4.2
jupyter_core==5.7.2
jupyter_latex_envs==1.4.6
jupyter_nbextensions_configurator==0.4.1
jupyterlab==2.3.2
jupyterlab-server==1.2.0
jupyterlab_pygments==0.3.0
jupyterlab_widgets==3.0.13
lxml==5.3.1
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
mistune==3.1.3
mypy-extensions==1.0.0
nbclient==0.10.2
nbconvert==7.16.6
nbformat==5.10.4
nest-asyncio==1.6.0
nodeenv==1.9.1
notebook==5.7.8
numpy==2.0.2
packaging @ file:///croot/packaging_1734472117206/work
pandocfilters==1.5.1
parso==0.8.4
pathspec==0.12.1
pexpect==4.9.0
platformdirs==4.3.7
pluggy @ file:///croot/pluggy_1733169602837/work
pre_commit==4.2.0
prometheus_client==0.21.1
prompt_toolkit==3.0.50
psutil==7.0.0
ptyprocess==0.7.0
pure_eval==0.2.3
-e git+https://github.com/nipype/pydra.git@7ceb4def20a07d7e4394ea69aed32ca376e14f73#egg=pydra
Pygments==2.19.1
PyLD==2.0.4
pytest @ file:///croot/pytest_1738938843180/work
pytest-cov==6.0.0
pytest-env==1.1.5
pytest-xdist==3.6.1
python-dateutil==2.9.0.post0
PyYAML==6.0.2
pyzmq==26.3.0
referencing==0.36.2
requests==2.32.3
rpds-py==0.24.0
Send2Trash==1.8.3
six==1.17.0
soupsieve==2.6
stack-data==0.6.3
terminado==0.13.3
tinycss2==1.4.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
tornado==4.5.3
traitlets==5.14.3
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
wcwidth==0.2.13
webencodings==0.5.1
widgetsnbextension==4.0.13
zipp==3.21.0

name: pydra
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - asttokens==3.0.0
      - attrs==25.3.0
      - beautifulsoup4==4.13.3
      - black==25.1.0
      - bleach==6.2.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cfgv==3.4.0
      - charset-normalizer==3.4.1
      - ci-info==0.3.0
      - click==8.1.8
      - cloudpickle==3.1.1
      - codecov==2.1.13
      - comm==0.2.2
      - coverage==7.8.0
      - debugpy==1.8.13
      - decorator==5.2.1
      - defusedxml==0.7.1
      - distlib==0.3.9
      - entrypoints==0.4
      - etelemetry==0.3.1
      - execnet==2.1.1
      - executing==2.2.0
      - fastjsonschema==2.21.1
      - filelock==3.18.0
      - frozendict==2.4.6
      - identify==2.6.9
      - idna==3.10
      - importlib-metadata==8.6.1
      - ipykernel==6.9.2
      - ipython==8.18.1
      - ipython-genutils==0.2.0
      - ipywidgets==8.1.5
      - jedi==0.19.2
      - jinja2==3.1.6
      - json5==0.10.0
      - jsonschema==4.23.0
      - jsonschema-specifications==2024.10.1
      - jupyter==1.1.1
      - jupyter-client==7.1.2
      - jupyter-console==6.4.4
      - jupyter-contrib-core==0.4.2
      - jupyter-contrib-nbextensions==0.5.1
      - jupyter-core==5.7.2
      - jupyter-highlight-selected-word==0.2.0
      - jupyter-latex-envs==1.4.6
      - jupyter-nbextensions-configurator==0.4.1
      - jupyterlab==2.3.2
      - jupyterlab-pygments==0.3.0
      - jupyterlab-server==1.2.0
      - jupyterlab-widgets==3.0.13
      - lxml==5.3.1
      - markupsafe==3.0.2
      - matplotlib-inline==0.1.7
      - mistune==3.1.3
      - mypy-extensions==1.0.0
      - nbclient==0.10.2
      - nbconvert==7.16.6
      - nbformat==5.10.4
      - nest-asyncio==1.6.0
      - nodeenv==1.9.1
      - notebook==5.7.8
      - numpy==2.0.2
      - pandocfilters==1.5.1
      - parso==0.8.4
      - pathspec==0.12.1
      - pexpect==4.9.0
      - platformdirs==4.3.7
      - pre-commit==4.2.0
      - prometheus-client==0.21.1
      - prompt-toolkit==3.0.50
      - psutil==7.0.0
      - ptyprocess==0.7.0
      - pure-eval==0.2.3
      - pydra==0.3.1+11.g7ceb4def
      - pygments==2.19.1
      - pyld==2.0.4
      - pytest-cov==6.0.0
      - pytest-env==1.1.5
      - pytest-xdist==3.6.1
      - python-dateutil==2.9.0.post0
      - pyyaml==6.0.2
      - pyzmq==26.3.0
      - referencing==0.36.2
      - requests==2.32.3
      - rpds-py==0.24.0
      - send2trash==1.8.3
      - six==1.17.0
      - soupsieve==2.6
      - stack-data==0.6.3
      - terminado==0.13.3
      - tinycss2==1.4.0
      - tornado==4.5.3
      - traitlets==5.14.3
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - widgetsnbextension==4.0.13
      - zipp==3.21.0
prefix: /opt/conda/envs/pydra

pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_1a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_1a[cf-result_submitter]
pydra/engine/tests/test_shelltask.py::test_shell_cmd_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_1_strip[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_1_strip[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2b[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_2b[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_3[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_4[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_5[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_6[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_7[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_1[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_2[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_2[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3b[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3b[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3c_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3c[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_3c[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4b[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4b[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4c_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_4d_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_5_nosubm[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_5_nosubm[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_5a_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_6[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_6[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_6a_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_6b[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_6b[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_7[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_7[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_7a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_7a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_8[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_8[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_1a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_1a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_2[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_2[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_3[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_state_3[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_state_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_inputspec_copyfile_state_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_2[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_2a[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_3[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_3a[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_state_1[cf] pydra/engine/tests/test_shelltask.py::test_wf_shell_cmd_ndst_1[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_1a[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_1a[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_1b_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_2[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_2[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_2a_exception[cf] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_3[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_3[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_4[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_4[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_5[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_5[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_state_outputspec_1[cf-result_no_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_state_outputspec_1[cf-result_submitter] pydra/engine/tests/test_shelltask.py::test_shell_cmd_outputspec_wf_1[cf]
pydra/engine/helpers.py
pydra/engine/helpers.py